diff --git a/Cargo.lock b/Cargo.lock index d0b1ccd..f3e11e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1068,17 +1068,13 @@ version = "0.1.0" dependencies = [ "anyhow", "axum 0.7.5", - "bus", "clap", - "dirs", "dotenv", "serde", "serde_json", "similar-asserts", - "sqlx", "tempfile", "tokio", - "tower-http", "tracing", "tracing-subscriber", "uuid", @@ -1118,15 +1114,19 @@ name = "hyperlog-tui" version = "0.1.0" dependencies = [ "anyhow", + "bus", "crossterm", "directories", + "dirs", "human-panic", "hyperlog-core", "itertools", "ratatui", "ropey", + "serde", "serde_json", "similar-asserts", + "tempfile", "tokio", "tracing", "tracing-subscriber", diff --git a/crates/hyperlog-core/Cargo.toml b/crates/hyperlog-core/Cargo.toml index 1df2f64..6a89252 100644 --- a/crates/hyperlog-core/Cargo.toml +++ b/crates/hyperlog-core/Cargo.toml @@ -13,18 +13,8 @@ dotenv.workspace = true axum.workspace = true serde = { version = "1.0.201", features = ["derive"] } -sqlx = { version = "0.7.4", features = [ - "runtime-tokio", - "tls-rustls", - "postgres", - "uuid", - "time", -] } uuid = { version = "1.8.0", features = ["v4"] } -tower-http = { version = "0.5.2", features = ["cors", "trace"] } serde_json = "1.0.117" -bus = "2.4.1" -dirs = "5.0.1" [dev-dependencies] similar-asserts = "1.5.0" diff --git a/crates/hyperlog-core/src/lib.rs b/crates/hyperlog-core/src/lib.rs index 3102947..f4ee9bc 100644 --- a/crates/hyperlog-core/src/lib.rs +++ b/crates/hyperlog-core/src/lib.rs @@ -1,11 +1 @@ -#![feature(map_try_insert)] - -pub mod commander; -pub mod querier; - -pub mod engine; -pub mod events; pub mod log; -pub mod shared_engine; -pub mod state; -pub mod storage; diff --git a/crates/hyperlog-protos/proto/hyperlog.proto b/crates/hyperlog-protos/proto/hyperlog.proto index e686ab2..5358ea2 100644 --- a/crates/hyperlog-protos/proto/hyperlog.proto +++ b/crates/hyperlog-protos/proto/hyperlog.proto @@ -3,14 +3,45 @@ syntax = "proto3"; package hyperlog; service Graph { - rpc SayHello (HelloRequest) returns (HelloReply); + rpc Get(GetRequest) returns (GetReply); } -message HelloRequest { - string name = 1; + +message UserGraphItem { + map items = 1; + +} +message SectionGraphItem { + map items = 1; } -message HelloReply { - string message = 1; +enum ItemState { + UNSPECIFIED = 0; + NOT_DONE = 1; + DONE = 2; +} + +message ItemGraphItem { + string title = 1; + string description = 2; + ItemState state = 3; +} + +message GraphItem { + string path = 1; + oneof contents { + UserGraphItem user = 2; + SectionGraphItem section = 3; + ItemGraphItem item = 4; + } +} + +message GetRequest { + string root = 1; + repeated string paths = 2; +} + +message GetReply { + repeated GraphItem items = 1; } diff --git a/crates/hyperlog-server/src/commands.rs b/crates/hyperlog-server/src/commands.rs new file mode 100644 index 0000000..4f10ab4 --- /dev/null +++ b/crates/hyperlog-server/src/commands.rs @@ -0,0 +1,97 @@ +use hyperlog_core::log::{GraphItem, ItemState}; + +pub enum Command { + CreateRoot { + root: String, + }, + CreateSection { + root: String, + path: Vec, + }, + CreateItem { + root: String, + path: Vec, + title: String, + description: String, + state: ItemState, + }, + UpdateItem { + root: String, + path: Vec, + title: String, + description: String, + state: ItemState, + }, + ToggleItem { + root: String, + path: Vec, + }, + Move { + root: String, + src: Vec, + dest: Vec, + }, +} + +pub struct Commander {} + +impl Commander { + pub fn execute(&self, cmd: Command) -> anyhow::Result<()> { + match cmd { + Command::CreateRoot { root } => todo!(), + Command::CreateSection { root, path } => todo!(), + Command::CreateItem { + root, + path, + title, + description, + state, + } => todo!(), + Command::UpdateItem { + root, + path, + title, + description, + state, + } => todo!(), + Command::ToggleItem { root, path } => todo!(), + Command::Move { root, src, dest } => todo!(), + } + + Ok(()) + } + + pub async fn create_root(&self, root: &str) -> anyhow::Result<()> { + todo!() + } + + pub async fn create(&self, root: &str, path: &[&str], item: GraphItem) -> anyhow::Result<()> { + todo!() + } + + pub async fn get(&self, root: &str, path: &[&str]) -> Option { + todo!() + } + + pub async fn section_move( + &self, + root: &str, + src_path: &[&str], + dest_path: &[&str], + ) -> anyhow::Result<()> { + todo!() + } + + pub async fn delete(&self, root: &str, path: &[&str]) -> anyhow::Result<()> { + todo!() + } + + pub async fn update_item( + &self, + root: &str, + path: &[&str], + item: &GraphItem, + ) -> anyhow::Result<()> { + todo!() + } +} diff --git a/crates/hyperlog-server/src/external_grpc.rs b/crates/hyperlog-server/src/external_grpc.rs new file mode 100644 index 0000000..b01afc7 --- /dev/null +++ b/crates/hyperlog-server/src/external_grpc.rs @@ -0,0 +1,82 @@ +use std::{collections::HashMap, net::SocketAddr}; + +use hyperlog_protos::hyperlog::{ + graph_server::{Graph, GraphServer}, + *, +}; +use tonic::{transport, Response}; + +use crate::{ + querier::{Querier, QuerierExt}, + state::SharedState, +}; + +pub struct Server { + querier: Querier, +} + +impl Server { + pub fn new(querier: Querier) -> Self { + Self { querier } + } +} + +#[tonic::async_trait] +impl Graph for Server { + async fn get( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + let msg = request.get_ref(); + + tracing::trace!("get: req({:?})", msg); + + Ok(Response::new(GetReply { + items: vec![ + GraphItem { + path: "some.path".into(), + contents: Some(graph_item::Contents::Item(ItemGraphItem { + title: "some-title".into(), + description: "some-description".into(), + state: ItemState::NotDone as i32, + })), + }, + GraphItem { + path: "some.path.section".into(), + contents: Some(graph_item::Contents::Section(SectionGraphItem { + items: HashMap::new(), + })), + }, + GraphItem { + path: "some.path".into(), + contents: Some(graph_item::Contents::User(UserGraphItem { + items: HashMap::new(), + })), + }, + ], + })) + } +} + +pub trait ServerExt { + fn grpc_server(&self) -> Server; +} + +impl ServerExt for SharedState { + fn grpc_server(&self) -> Server { + Server::new(self.querier()) + } +} + +pub async fn serve(state: &SharedState, host: SocketAddr) -> anyhow::Result<()> { + tracing::info!("listening on {}", host); + + let graph_server = state.grpc_server(); + + transport::Server::builder() + .add_service(GraphServer::new(graph_server)) + .serve(host) + .await?; + + Ok(()) +} diff --git a/crates/hyperlog-server/src/lib.rs b/crates/hyperlog-server/src/lib.rs index a63957a..00564a8 100644 --- a/crates/hyperlog-server/src/lib.rs +++ b/crates/hyperlog-server/src/lib.rs @@ -2,49 +2,13 @@ use std::{net::SocketAddr, sync::Arc}; use crate::state::{SharedState, State}; +mod external_grpc; mod external_http; mod internal_http; -mod external_grpc { - use std::net::SocketAddr; - use hyperlog_protos::hyperlog::{ - graph_server::{Graph, GraphServer}, - HelloReply, HelloRequest, - }; - use tonic::{transport, Response}; +mod commands; +mod querier; - use crate::state::SharedState; - - #[derive(Default)] - struct Server {} - - #[tonic::async_trait] - impl Graph for Server { - async fn say_hello( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status> { - tracing::info!("received hello request"); - - Ok(Response::new(HelloReply { - message: "hello".into(), - })) - } - } - - pub async fn serve(state: &SharedState, host: SocketAddr) -> anyhow::Result<()> { - tracing::info!("listening on {}", host); - - let graph_server = Server::default(); - - transport::Server::builder() - .add_service(GraphServer::new(graph_server)) - .serve(host) - .await?; - - Ok(()) - } -} mod state; #[derive(Clone)] diff --git a/crates/hyperlog-server/src/querier.rs b/crates/hyperlog-server/src/querier.rs new file mode 100644 index 0000000..cdd2cfe --- /dev/null +++ b/crates/hyperlog-server/src/querier.rs @@ -0,0 +1,33 @@ +use hyperlog_core::log::GraphItem; + +use crate::state::SharedState; + +pub struct Querier {} + +impl Querier { + pub fn new() -> Self { + Self {} + } + + pub fn get_available_roots(&self) -> Option> { + todo!() + } + + pub fn get( + &self, + root: &str, + path: impl IntoIterator>, + ) -> Option { + todo!() + } +} + +pub trait QuerierExt { + fn querier(&self) -> Querier; +} + +impl QuerierExt for SharedState { + fn querier(&self) -> Querier { + Querier::new() + } +} diff --git a/crates/hyperlog-tui/Cargo.toml b/crates/hyperlog-tui/Cargo.toml index 75f91d4..631286a 100644 --- a/crates/hyperlog-tui/Cargo.toml +++ b/crates/hyperlog-tui/Cargo.toml @@ -11,6 +11,7 @@ anyhow.workspace = true tokio.workspace = true tracing.workspace = true tracing-subscriber.workspace = true +serde.workspace = true serde_json.workspace = true itertools.workspace = true @@ -19,6 +20,9 @@ crossterm = { version = "0.27.0", features = ["event-stream"] } directories = "5.0.1" human-panic = "2.0.0" ropey = "1.6.1" +bus = "2.4.1" +dirs = "5.0.1" [dev-dependencies] similar-asserts = "1.5.0" +tempfile = "3.10.1" diff --git a/crates/hyperlog-tui/src/app.rs b/crates/hyperlog-tui/src/app.rs index 6635460..1109ca6 100644 --- a/crates/hyperlog-tui/src/app.rs +++ b/crates/hyperlog-tui/src/app.rs @@ -5,7 +5,7 @@ use ratatui::{ }; use crate::{ - command_parser::CommandParser, commands::IntoCommand, + command_parser::CommandParser, commander, commands::IntoCommand, components::graph_explorer::GraphExplorer, state::SharedState, Msg, }; @@ -26,7 +26,7 @@ pub enum Dialog { } impl Dialog { - pub fn get_command(&self) -> Option { + pub fn get_command(&self) -> Option { match self { Dialog::CreateItem { state } => state.get_command(), Dialog::EditItem { state } => state.get_command(), diff --git a/crates/hyperlog-tui/src/app/dialog/create_item.rs b/crates/hyperlog-tui/src/app/dialog/create_item.rs index a8e397c..37b20ac 100644 --- a/crates/hyperlog-tui/src/app/dialog/create_item.rs +++ b/crates/hyperlog-tui/src/app/dialog/create_item.rs @@ -1,7 +1,7 @@ use itertools::Itertools; use ratatui::{prelude::*, widgets::*}; -use crate::models::Msg; +use crate::{commander, models::Msg}; use super::{InputBuffer, InputField}; @@ -61,7 +61,7 @@ impl CreateItemState { Ok(()) } - pub fn get_command(&self) -> Option { + pub fn get_command(&self) -> Option { let title = self.title.string(); let description = self.description.string(); @@ -69,7 +69,7 @@ impl CreateItemState { let mut path = self.path.clone(); path.push(title.replace([' ', '.'], "-")); - Some(hyperlog_core::commander::Command::CreateItem { + Some(commander::Command::CreateItem { root: self.root.clone(), path, title: title.trim().into(), diff --git a/crates/hyperlog-tui/src/app/dialog/edit_item.rs b/crates/hyperlog-tui/src/app/dialog/edit_item.rs index 2e364f3..62598bc 100644 --- a/crates/hyperlog-tui/src/app/dialog/edit_item.rs +++ b/crates/hyperlog-tui/src/app/dialog/edit_item.rs @@ -2,7 +2,7 @@ use hyperlog_core::log::GraphItem; use itertools::Itertools; use ratatui::{prelude::*, widgets::*}; -use crate::models::Msg; +use crate::{commander, models::Msg}; use super::{InputBuffer, InputField}; @@ -82,14 +82,14 @@ impl EditItemState { Ok(()) } - pub fn get_command(&self) -> Option { + pub fn get_command(&self) -> Option { let title = self.title.string(); let description = self.description.string(); if !title.is_empty() { let path = self.path.clone(); - Some(hyperlog_core::commander::Command::UpdateItem { + Some(commander::Command::UpdateItem { root: self.root.clone(), path, title: title.trim().into(), diff --git a/crates/hyperlog-core/src/commander.rs b/crates/hyperlog-tui/src/commander.rs similarity index 96% rename from crates/hyperlog-core/src/commander.rs rename to crates/hyperlog-tui/src/commander.rs index 94d9e67..f15558f 100644 --- a/crates/hyperlog-core/src/commander.rs +++ b/crates/hyperlog-tui/src/commander.rs @@ -1,13 +1,9 @@ use std::collections::BTreeMap; +use hyperlog_core::log::{GraphItem, ItemState}; use serde::Serialize; -use crate::{ - events::Events, - log::{GraphItem, ItemState}, - shared_engine::SharedEngine, - storage::Storage, -}; +use crate::{events::Events, shared_engine::SharedEngine, storage::Storage}; #[derive(Serialize, PartialEq, Eq, Debug, Clone)] pub enum Command { diff --git a/crates/hyperlog-tui/src/components/graph_explorer.rs b/crates/hyperlog-tui/src/components/graph_explorer.rs index 5c52582..3dbc165 100644 --- a/crates/hyperlog-tui/src/components/graph_explorer.rs +++ b/crates/hyperlog-tui/src/components/graph_explorer.rs @@ -3,7 +3,7 @@ use hyperlog_core::log::GraphItem; use ratatui::{prelude::*, widgets::*}; use crate::{ - command_parser::Commands, components::movement_graph::GraphItemType, models::Msg, + command_parser::Commands, commander, components::movement_graph::GraphItemType, models::Msg, state::SharedState, }; @@ -196,12 +196,12 @@ impl<'a> GraphExplorer<'a> { let mut path = self.get_current_path(); path.push(name.replace(" ", "-").replace(".", "-")); - self.state.commander.execute( - hyperlog_core::commander::Command::CreateSection { + self.state + .commander + .execute(commander::Command::CreateSection { root: self.inner.root.clone(), path, - }, - )?; + })?; } } Commands::Edit => { @@ -247,7 +247,7 @@ impl<'a> GraphExplorer<'a> { self.state .commander - .execute(hyperlog_core::commander::Command::ToggleItem { + .execute(commander::Command::ToggleItem { root: self.inner.root.to_string(), path: self.get_current_path(), })?; diff --git a/crates/hyperlog-core/src/state.rs b/crates/hyperlog-tui/src/core_state.rs similarity index 100% rename from crates/hyperlog-core/src/state.rs rename to crates/hyperlog-tui/src/core_state.rs diff --git a/crates/hyperlog-core/src/engine.rs b/crates/hyperlog-tui/src/engine.rs similarity index 98% rename from crates/hyperlog-core/src/engine.rs rename to crates/hyperlog-tui/src/engine.rs index ec3bf39..6d497fe 100644 --- a/crates/hyperlog-core/src/engine.rs +++ b/crates/hyperlog-tui/src/engine.rs @@ -1,8 +1,7 @@ use std::{collections::BTreeMap, fmt::Display}; use anyhow::{anyhow, Context}; - -use crate::log::{Graph, GraphItem, ItemState}; +use hyperlog_core::log::{Graph, GraphItem, ItemState}; #[derive(Default)] pub struct Engine { @@ -218,10 +217,9 @@ impl Display for Engine { mod test { use std::collections::BTreeMap; + use hyperlog_core::log::{GraphItem, ItemState}; use similar_asserts::assert_eq; - use crate::log::{GraphItem, ItemState}; - use super::Engine; #[test] @@ -249,7 +247,7 @@ mod test { .create( "kjuulh", &["some-section"], - crate::log::GraphItem::Section(BTreeMap::default()), + GraphItem::Section(BTreeMap::default()), ) .unwrap(); @@ -275,7 +273,7 @@ mod test { .create( "kjuulh", &["some-section"], - crate::log::GraphItem::Section(BTreeMap::default()), + GraphItem::Section(BTreeMap::default()), ) .unwrap(); @@ -283,7 +281,7 @@ mod test { .create( "kjuulh", &["some-section", "some-sub-section"], - crate::log::GraphItem::Section(BTreeMap::default()), + GraphItem::Section(BTreeMap::default()), ) .unwrap(); diff --git a/crates/hyperlog-core/src/events.rs b/crates/hyperlog-tui/src/events.rs similarity index 100% rename from crates/hyperlog-core/src/events.rs rename to crates/hyperlog-tui/src/events.rs diff --git a/crates/hyperlog-tui/src/lib.rs b/crates/hyperlog-tui/src/lib.rs index 5950f49..2142cc9 100644 --- a/crates/hyperlog-tui/src/lib.rs +++ b/crates/hyperlog-tui/src/lib.rs @@ -1,3 +1,4 @@ +#![feature(map_try_insert)] #![feature(fn_traits)] use std::{io::Stdout, time::Duration}; @@ -6,8 +7,8 @@ use anyhow::{Context, Result}; use app::{render_app, App}; use commands::IntoCommand; use components::graph_explorer::GraphExplorer; +use core_state::State; use crossterm::event::{self, Event, KeyCode}; -use hyperlog_core::state::State; use models::{EditMsg, Msg}; use ratatui::{backend::CrosstermBackend, Terminal}; @@ -19,7 +20,16 @@ pub(crate) mod app; pub(crate) mod command_parser; pub(crate) mod commands; pub(crate) mod components; -pub(crate) mod state; + +pub mod commander; +pub mod core_state; +pub mod shared_engine; +pub mod state; + +mod engine; +mod events; +mod querier; +mod storage; mod logging; mod terminal; diff --git a/crates/hyperlog-core/src/querier.rs b/crates/hyperlog-tui/src/querier.rs similarity index 91% rename from crates/hyperlog-core/src/querier.rs rename to crates/hyperlog-tui/src/querier.rs index e7bfe57..28c59a3 100644 --- a/crates/hyperlog-core/src/querier.rs +++ b/crates/hyperlog-tui/src/querier.rs @@ -1,4 +1,6 @@ -use crate::{log::GraphItem, shared_engine::SharedEngine}; +use hyperlog_core::log::GraphItem; + +use crate::shared_engine::SharedEngine; pub struct Querier { engine: SharedEngine, diff --git a/crates/hyperlog-core/src/shared_engine.rs b/crates/hyperlog-tui/src/shared_engine.rs similarity index 96% rename from crates/hyperlog-core/src/shared_engine.rs rename to crates/hyperlog-tui/src/shared_engine.rs index a1be248..b4feb8e 100644 --- a/crates/hyperlog-core/src/shared_engine.rs +++ b/crates/hyperlog-tui/src/shared_engine.rs @@ -1,6 +1,8 @@ use std::sync::{Arc, RwLock}; -use crate::{engine::Engine, log::GraphItem}; +use hyperlog_core::log::GraphItem; + +use crate::engine::Engine; #[derive(Clone)] pub struct SharedEngine { diff --git a/crates/hyperlog-tui/src/state.rs b/crates/hyperlog-tui/src/state.rs index 38188d1..6c6b6b9 100644 --- a/crates/hyperlog-tui/src/state.rs +++ b/crates/hyperlog-tui/src/state.rs @@ -1,6 +1,6 @@ use std::{ops::Deref, sync::Arc}; -use hyperlog_core::state::State; +use crate::core_state::State; #[derive(Clone)] pub struct SharedState { diff --git a/crates/hyperlog-core/src/storage.rs b/crates/hyperlog-tui/src/storage.rs similarity index 99% rename from crates/hyperlog-core/src/storage.rs rename to crates/hyperlog-tui/src/storage.rs index e073820..d33bd2c 100644 --- a/crates/hyperlog-core/src/storage.rs +++ b/crates/hyperlog-tui/src/storage.rs @@ -149,10 +149,9 @@ impl Storage { mod test { use std::collections::BTreeMap; + use hyperlog_core::log::GraphItem; use similar_asserts::assert_eq; - use crate::log::GraphItem; - use super::*; #[test] diff --git a/crates/hyperlog/src/cli.rs b/crates/hyperlog/src/cli.rs index 66d8f45..f6d52c7 100644 --- a/crates/hyperlog/src/cli.rs +++ b/crates/hyperlog/src/cli.rs @@ -1,7 +1,7 @@ use std::net::SocketAddr; use clap::{Parser, Subcommand}; -use hyperlog_core::{commander, state}; +use hyperlog_tui::{commander, core_state::State, state}; #[derive(Parser)] #[command(author, version, about, long_about = None)] @@ -90,7 +90,7 @@ pub async fn execute() -> anyhow::Result<()> { .await?; } Some(Commands::Exec { commands }) => { - let state = state::State::new()?; + let state = State::new()?; match commands { ExecCommands::CreateRoot { root } => state .commander @@ -109,7 +109,7 @@ pub async fn execute() -> anyhow::Result<()> { } } Some(Commands::Query { commands }) => { - let state = state::State::new()?; + let state = State::new()?; match commands { QueryCommands::Get { root, path } => { let res = state.querier.get( @@ -126,23 +126,23 @@ pub async fn execute() -> anyhow::Result<()> { } } Some(Commands::CreateRoot { name }) => { - let state = state::State::new()?; + let state = State::new()?; state .commander .execute(commander::Command::CreateRoot { root: name })?; println!("Root was successfully created, now run:\n\n$ hyperlog"); } Some(Commands::Info {}) => { - let state = state::State::new()?; + let state = State::new()?; println!("graph stored at: {}", state.storage.info()?) } Some(Commands::ClearLock {}) => { - let state = state::State::new()?; + let state = State::new()?; state.storage.clear_lock_file(); println!("cleared lock file"); } None => { - let state = state::State::new()?; + let state = State::new()?; hyperlog_tui::execute(state).await?; } } diff --git a/scripts/dev.sh b/scripts/dev.sh index 2c81c29..1185cd9 100755 --- a/scripts/dev.sh +++ b/scripts/dev.sh @@ -12,4 +12,4 @@ tear_down() { trap tear_down SIGINT -RUST_LOG=info,hyperlog=trace cargo run -F include_server -- serve +RUST_LOG=info,hyperlog=trace cargo watch -x 'run -F include_server -- serve' diff --git a/templates/docker-compose.yaml b/templates/docker-compose.yaml index 8fae72a..88ec983 100644 --- a/templates/docker-compose.yaml +++ b/templates/docker-compose.yaml @@ -1,4 +1,3 @@ -version: "3" services: crdb: restart: 'always' @@ -11,5 +10,5 @@ services: retries: 5 start_period: '20s' ports: - - 8080:8080 + - 28080:8080 - '26257:26257'