feat: abstract commander
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
This commit is contained in:
parent
64d59e069f
commit
76f1c87663
@ -2,16 +2,6 @@ syntax = "proto3";
|
|||||||
|
|
||||||
package hyperlog;
|
package hyperlog;
|
||||||
|
|
||||||
service Graph {
|
|
||||||
rpc GetAvailableRoots(GetAvailableRootsRequest) returns (GetAvailableRootsResponse);
|
|
||||||
rpc Get(GetRequest) returns (GetReply);
|
|
||||||
}
|
|
||||||
|
|
||||||
message GetAvailableRootsRequest {}
|
|
||||||
message GetAvailableRootsResponse {
|
|
||||||
repeated string roots = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message UserGraphItem {
|
message UserGraphItem {
|
||||||
map<string, GraphItem> items = 1;
|
map<string, GraphItem> items = 1;
|
||||||
|
|
||||||
@ -41,6 +31,17 @@ message GraphItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
service Graph {
|
||||||
|
rpc GetAvailableRoots(GetAvailableRootsRequest) returns (GetAvailableRootsResponse);
|
||||||
|
rpc Get(GetRequest) returns (GetReply);
|
||||||
|
rpc CreateSection(CreateSectionRequest) returns (CreateSectionResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetAvailableRootsRequest {}
|
||||||
|
message GetAvailableRootsResponse {
|
||||||
|
repeated string roots = 1;
|
||||||
|
}
|
||||||
|
|
||||||
message GetRequest {
|
message GetRequest {
|
||||||
string root = 1;
|
string root = 1;
|
||||||
repeated string paths = 2;
|
repeated string paths = 2;
|
||||||
@ -50,3 +51,7 @@ message GetReply {
|
|||||||
GraphItem item = 1;
|
GraphItem item = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
message CreateSectionRequest {}
|
||||||
|
message CreateSectionResponse {}
|
||||||
|
|
||||||
|
@ -64,6 +64,16 @@ impl Graph for Server {
|
|||||||
roots: vec!["kjuulh".into()],
|
roots: vec!["kjuulh".into()],
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn create_section(
|
||||||
|
&self,
|
||||||
|
request: tonic::Request<CreateSectionRequest>,
|
||||||
|
) -> std::result::Result<tonic::Response<CreateSectionResponse>, tonic::Status> {
|
||||||
|
let req = request.into_inner();
|
||||||
|
tracing::trace!("create section: req({:?})", req);
|
||||||
|
|
||||||
|
Ok(Response::new(CreateSectionResponse {}))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ServerExt {
|
pub trait ServerExt {
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
use hyperlog_core::log::ItemState;
|
use hyperlog_core::log::ItemState;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use tonic::transport::Channel;
|
||||||
|
|
||||||
use crate::{events::Events, shared_engine::SharedEngine, storage::Storage};
|
use crate::{events::Events, shared_engine::SharedEngine, storage::Storage};
|
||||||
|
|
||||||
|
mod local;
|
||||||
|
mod remote;
|
||||||
|
|
||||||
#[derive(Serialize, PartialEq, Eq, Debug, Clone)]
|
#[derive(Serialize, PartialEq, Eq, Debug, Clone)]
|
||||||
pub enum Command {
|
pub enum Command {
|
||||||
CreateRoot {
|
CreateRoot {
|
||||||
@ -40,6 +44,7 @@ pub enum Command {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
enum CommanderVariant {
|
enum CommanderVariant {
|
||||||
Local(local::Commander),
|
Local(local::Commander),
|
||||||
|
Remote(remote::Commander),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -54,97 +59,16 @@ impl Commander {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn remote(channel: Channel) -> anyhow::Result<Self> {
|
||||||
|
Ok(Self {
|
||||||
|
variant: CommanderVariant::Remote(remote::Commander::new(channel)?),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn execute(&self, cmd: Command) -> anyhow::Result<()> {
|
pub async fn execute(&self, cmd: Command) -> anyhow::Result<()> {
|
||||||
match &self.variant {
|
match &self.variant {
|
||||||
CommanderVariant::Local(commander) => commander.execute(cmd),
|
CommanderVariant::Local(commander) => commander.execute(cmd),
|
||||||
}
|
CommanderVariant::Remote(commander) => commander.execute(cmd).await,
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod local {
|
|
||||||
use std::collections::BTreeMap;
|
|
||||||
|
|
||||||
use hyperlog_core::log::GraphItem;
|
|
||||||
|
|
||||||
use crate::{events::Events, shared_engine::SharedEngine, storage::Storage};
|
|
||||||
|
|
||||||
use super::Command;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Commander {
|
|
||||||
engine: SharedEngine,
|
|
||||||
storage: Storage,
|
|
||||||
events: Events,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Commander {
|
|
||||||
pub fn new(engine: SharedEngine, storage: Storage, events: Events) -> anyhow::Result<Self> {
|
|
||||||
Ok(Self {
|
|
||||||
engine,
|
|
||||||
storage,
|
|
||||||
events,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn execute(&self, cmd: Command) -> anyhow::Result<()> {
|
|
||||||
tracing::debug!("executing event: {}", serde_json::to_string(&cmd)?);
|
|
||||||
|
|
||||||
match cmd.clone() {
|
|
||||||
Command::CreateRoot { root } => {
|
|
||||||
self.engine.create_root(&root)?;
|
|
||||||
}
|
|
||||||
Command::CreateSection { root, path } => {
|
|
||||||
self.engine.create(
|
|
||||||
&root,
|
|
||||||
&path.iter().map(|p| p.as_str()).collect::<Vec<_>>(),
|
|
||||||
GraphItem::Section(BTreeMap::default()),
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
Command::CreateItem {
|
|
||||||
root,
|
|
||||||
path,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
state,
|
|
||||||
} => self.engine.create(
|
|
||||||
&root,
|
|
||||||
&path.iter().map(|p| p.as_str()).collect::<Vec<_>>(),
|
|
||||||
GraphItem::Item {
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
state,
|
|
||||||
},
|
|
||||||
)?,
|
|
||||||
Command::Move { root, src, dest } => self.engine.section_move(
|
|
||||||
&root,
|
|
||||||
&src.iter().map(|p| p.as_str()).collect::<Vec<_>>(),
|
|
||||||
&dest.iter().map(|p| p.as_str()).collect::<Vec<_>>(),
|
|
||||||
)?,
|
|
||||||
Command::ToggleItem { root, path } => self
|
|
||||||
.engine
|
|
||||||
.toggle_item(&root, &path.iter().map(|p| p.as_str()).collect::<Vec<_>>())?,
|
|
||||||
Command::UpdateItem {
|
|
||||||
root,
|
|
||||||
path,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
state,
|
|
||||||
} => self.engine.update_item(
|
|
||||||
&root,
|
|
||||||
&path.iter().map(|p| p.as_str()).collect::<Vec<_>>(),
|
|
||||||
GraphItem::Item {
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
state,
|
|
||||||
},
|
|
||||||
)?,
|
|
||||||
}
|
|
||||||
|
|
||||||
self.storage.store(&self.engine)?;
|
|
||||||
|
|
||||||
self.events.enque_command(cmd)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
85
crates/hyperlog-tui/src/commander/local.rs
Normal file
85
crates/hyperlog-tui/src/commander/local.rs
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
use hyperlog_core::log::GraphItem;
|
||||||
|
|
||||||
|
use crate::{events::Events, shared_engine::SharedEngine, storage::Storage};
|
||||||
|
|
||||||
|
use super::Command;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Commander {
|
||||||
|
engine: SharedEngine,
|
||||||
|
storage: Storage,
|
||||||
|
events: Events,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Commander {
|
||||||
|
pub fn new(engine: SharedEngine, storage: Storage, events: Events) -> anyhow::Result<Self> {
|
||||||
|
Ok(Self {
|
||||||
|
engine,
|
||||||
|
storage,
|
||||||
|
events,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execute(&self, cmd: Command) -> anyhow::Result<()> {
|
||||||
|
tracing::debug!("executing event: {}", serde_json::to_string(&cmd)?);
|
||||||
|
|
||||||
|
match cmd.clone() {
|
||||||
|
Command::CreateRoot { root } => {
|
||||||
|
self.engine.create_root(&root)?;
|
||||||
|
}
|
||||||
|
Command::CreateSection { root, path } => {
|
||||||
|
self.engine.create(
|
||||||
|
&root,
|
||||||
|
&path.iter().map(|p| p.as_str()).collect::<Vec<_>>(),
|
||||||
|
GraphItem::Section(BTreeMap::default()),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Command::CreateItem {
|
||||||
|
root,
|
||||||
|
path,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
state,
|
||||||
|
} => self.engine.create(
|
||||||
|
&root,
|
||||||
|
&path.iter().map(|p| p.as_str()).collect::<Vec<_>>(),
|
||||||
|
GraphItem::Item {
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
state,
|
||||||
|
},
|
||||||
|
)?,
|
||||||
|
Command::Move { root, src, dest } => self.engine.section_move(
|
||||||
|
&root,
|
||||||
|
&src.iter().map(|p| p.as_str()).collect::<Vec<_>>(),
|
||||||
|
&dest.iter().map(|p| p.as_str()).collect::<Vec<_>>(),
|
||||||
|
)?,
|
||||||
|
Command::ToggleItem { root, path } => self
|
||||||
|
.engine
|
||||||
|
.toggle_item(&root, &path.iter().map(|p| p.as_str()).collect::<Vec<_>>())?,
|
||||||
|
Command::UpdateItem {
|
||||||
|
root,
|
||||||
|
path,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
state,
|
||||||
|
} => self.engine.update_item(
|
||||||
|
&root,
|
||||||
|
&path.iter().map(|p| p.as_str()).collect::<Vec<_>>(),
|
||||||
|
GraphItem::Item {
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
state,
|
||||||
|
},
|
||||||
|
)?,
|
||||||
|
}
|
||||||
|
|
||||||
|
self.storage.store(&self.engine)?;
|
||||||
|
|
||||||
|
self.events.enque_command(cmd)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
98
crates/hyperlog-tui/src/commander/remote.rs
Normal file
98
crates/hyperlog-tui/src/commander/remote.rs
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
use hyperlog_protos::hyperlog::{graph_client::GraphClient, *};
|
||||||
|
use tonic::transport::Channel;
|
||||||
|
|
||||||
|
use super::Command;
|
||||||
|
|
||||||
|
#[allow(dead_code, unused_variables)]
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Commander {
|
||||||
|
channel: Channel,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code, unused_variables)]
|
||||||
|
impl Commander {
|
||||||
|
pub fn new(channel: Channel) -> anyhow::Result<Self> {
|
||||||
|
Ok(Self { channel })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn execute(&self, cmd: Command) -> anyhow::Result<()> {
|
||||||
|
tracing::debug!("executing event: {}", serde_json::to_string(&cmd)?);
|
||||||
|
|
||||||
|
match cmd.clone() {
|
||||||
|
Command::CreateRoot { root } => {
|
||||||
|
todo!()
|
||||||
|
//self.engine.create_root(&root)?;
|
||||||
|
}
|
||||||
|
Command::CreateSection { root, path } => {
|
||||||
|
let channel = self.channel.clone();
|
||||||
|
|
||||||
|
let mut client = GraphClient::new(channel);
|
||||||
|
|
||||||
|
let request = tonic::Request::new(CreateSectionRequest {});
|
||||||
|
let response = client.create_section(request).await?;
|
||||||
|
let res = response.into_inner();
|
||||||
|
|
||||||
|
// self.engine.create(
|
||||||
|
// &root,
|
||||||
|
// &path.iter().map(|p| p.as_str()).collect::<Vec<_>>(),
|
||||||
|
// GraphItem::Section(BTreeMap::default()),
|
||||||
|
// )?;
|
||||||
|
}
|
||||||
|
Command::CreateItem {
|
||||||
|
root,
|
||||||
|
path,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
state,
|
||||||
|
} => {
|
||||||
|
todo!()
|
||||||
|
// self.engine.create(
|
||||||
|
// &root,
|
||||||
|
// &path.iter().map(|p| p.as_str()).collect::<Vec<_>>(),
|
||||||
|
// GraphItem::Item {
|
||||||
|
// title,
|
||||||
|
// description,
|
||||||
|
// state,
|
||||||
|
// },
|
||||||
|
// )?
|
||||||
|
}
|
||||||
|
Command::Move { root, src, dest } => {
|
||||||
|
todo!()
|
||||||
|
// self.engine.section_move(
|
||||||
|
// &root,
|
||||||
|
// &src.iter().map(|p| p.as_str()).collect::<Vec<_>>(),
|
||||||
|
// &dest.iter().map(|p| p.as_str()).collect::<Vec<_>>(),
|
||||||
|
// )?
|
||||||
|
}
|
||||||
|
Command::ToggleItem { root, path } => {
|
||||||
|
todo!()
|
||||||
|
// self
|
||||||
|
// .engine
|
||||||
|
// .toggle_item(&root, &path.iter().map(|p| p.as_str()).collect::<Vec<_>>())?
|
||||||
|
}
|
||||||
|
Command::UpdateItem {
|
||||||
|
root,
|
||||||
|
path,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
state,
|
||||||
|
} => {
|
||||||
|
todo!()
|
||||||
|
// self.engine.update_item(
|
||||||
|
// &root,
|
||||||
|
// &path.iter().map(|p| p.as_str()).collect::<Vec<_>>(),
|
||||||
|
// GraphItem::Item {
|
||||||
|
// title,
|
||||||
|
// description,
|
||||||
|
// state,
|
||||||
|
// },
|
||||||
|
// )?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// self.storage.store(&self.engine)?;
|
||||||
|
// self.events.enque_command(cmd)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@ use itertools::Itertools;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
commander::{self, Commander},
|
commander::{self, Commander},
|
||||||
models::IOEvent,
|
models::{IOEvent, Msg},
|
||||||
state::SharedState,
|
state::SharedState,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ impl CreateItemCommand {
|
|||||||
|
|
||||||
super::Command::new(|dispatch| {
|
super::Command::new(|dispatch| {
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
dispatch.send(crate::models::Msg::ItemCreated(IOEvent::Initialized));
|
dispatch.send(Msg::ItemCreated(IOEvent::Initialized));
|
||||||
|
|
||||||
match self
|
match self
|
||||||
.commander
|
.commander
|
||||||
@ -50,12 +50,10 @@ impl CreateItemCommand {
|
|||||||
{
|
{
|
||||||
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
||||||
}
|
}
|
||||||
dispatch.send(crate::models::Msg::ItemCreated(IOEvent::Success(())));
|
dispatch.send(Msg::ItemCreated(IOEvent::Success(())));
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
dispatch.send(crate::models::Msg::ItemCreated(IOEvent::Failure(
|
dispatch.send(Msg::ItemCreated(IOEvent::Failure(e.to_string())));
|
||||||
e.to_string(),
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use tonic::transport::Channel;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
commander::Commander, events::Events, querier::Querier, shared_engine::SharedEngine,
|
commander::Commander, events::Events, querier::Querier, shared_engine::SharedEngine,
|
||||||
storage::Storage,
|
storage::Storage,
|
||||||
@ -25,14 +27,21 @@ impl State {
|
|||||||
let events = Events::default();
|
let events = Events::default();
|
||||||
let engine = SharedEngine::from(engine);
|
let engine = SharedEngine::from(engine);
|
||||||
|
|
||||||
let querier = match backend {
|
let (querier, commander) = match backend {
|
||||||
Backend::Local => Querier::local(&engine),
|
Backend::Local => (
|
||||||
Backend::Remote => Querier::remote().await?,
|
Querier::local(&engine),
|
||||||
};
|
Commander::local(engine.clone(), storage.clone(), events.clone())?,
|
||||||
|
),
|
||||||
|
Backend::Remote => {
|
||||||
|
let channel = Channel::from_static("http://localhost:4000")
|
||||||
|
.connect()
|
||||||
|
.await?;
|
||||||
|
|
||||||
let commander = match backend {
|
(
|
||||||
Backend::Local => Commander::local(engine.clone(), storage.clone(), events.clone())?,
|
Querier::remote(channel.clone()).await?,
|
||||||
Backend::Remote => todo!(),
|
Commander::remote(channel)?,
|
||||||
|
)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use hyperlog_core::log::GraphItem;
|
use hyperlog_core::log::GraphItem;
|
||||||
|
use tonic::transport::Channel;
|
||||||
|
|
||||||
use crate::shared_engine::SharedEngine;
|
use crate::shared_engine::SharedEngine;
|
||||||
|
|
||||||
@ -23,9 +24,9 @@ impl Querier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn remote() -> anyhow::Result<Self> {
|
pub async fn remote(channel: Channel) -> anyhow::Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
variant: QuerierVariant::Remote(remote::Querier::new().await?),
|
variant: QuerierVariant::Remote(remote::Querier::new(channel).await?),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,11 +15,7 @@ pub struct Querier {
|
|||||||
|
|
||||||
#[allow(dead_code, unused_variables)]
|
#[allow(dead_code, unused_variables)]
|
||||||
impl Querier {
|
impl Querier {
|
||||||
pub async fn new() -> anyhow::Result<Self> {
|
pub async fn new(channel: Channel) -> anyhow::Result<Self> {
|
||||||
let channel = Channel::from_static("http://localhost:4000")
|
|
||||||
.connect()
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(Self { channel })
|
Ok(Self { channel })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user