diff --git a/side-node/src/list_transaction_crdt.rs b/side-node/src/list_transaction_crdt.rs index cee3033..a2e8057 100644 --- a/side-node/src/list_transaction_crdt.rs +++ b/side-node/src/list_transaction_crdt.rs @@ -15,8 +15,8 @@ use crate::keys; #[add_crdt_fields] #[derive(Clone, CrdtNode, Serialize, Deserialize)] -pub(crate) struct CrdtList { - pub(crate) list: ListCrdt, // switch to Transaction as soon as char is working +pub(crate) struct TransactionList { + pub(crate) list: ListCrdt, } /// A fake Transaction struct we can use as a simulated payload @@ -28,33 +28,33 @@ pub(crate) struct Transaction { amount: f64, } -pub(crate) fn new(side_dir: PathBuf) -> (BaseCrdt, Ed25519KeyPair) { +pub(crate) fn new(side_dir: PathBuf) -> (BaseCrdt, Ed25519KeyPair) { let keys = keys::load_from_file(side_dir); - let bft_crdt = BaseCrdt::::new(&keys); + let bft_crdt = BaseCrdt::::new(&keys); println!("Author is {}", keys.public().to_string()); (bft_crdt, keys) } pub(crate) fn create( - bft_crdt: &mut BaseCrdt, + bft_crdt: &mut BaseCrdt, keys: &Ed25519KeyPair, ) -> bft_json_crdt::json_crdt::SignedOp { // generate a placeholder transaction - let transaction = generate_transaction(keys.public().to_string()); + let transaction = fake_transaction(keys.public().to_string()); // next job is to keep adding to this guy - let next = bft_crdt.doc.list.ops.len(); + let last = bft_crdt.doc.list.ops.last().expect("couldn't find last op"); let signed_op = bft_crdt .doc .list - .insert_idx(next - 1, transaction.clone()) + .insert(last.id, transaction.clone()) .sign(&keys); signed_op } -fn generate_transaction(pubkey: String) -> Value { +fn fake_transaction(from_pubkey: String) -> Value { json!({ - "from": pubkey, + "from": from_pubkey, "to": "Bob", "amount": 1 }) diff --git a/side-node/src/main.rs b/side-node/src/main.rs index f369ea6..9a65fb9 100644 --- a/side-node/src/main.rs +++ b/side-node/src/main.rs @@ -1,9 +1,14 @@ +use bft_json_crdt::json_crdt::BaseCrdt; use cli::{parse_args, Commands}; +use list_transaction_crdt::TransactionList; +use node::SideNode; +use websocket::WebSocketClient; pub(crate) mod cli; pub(crate) mod init; pub(crate) mod keys; pub(crate) mod list_transaction_crdt; +pub(crate) mod node; pub(crate) mod utils; pub(crate) mod websocket; @@ -17,20 +22,23 @@ async fn main() { name: name.to_string(), }; - let _ = init::init(home(name), config); + let _ = init::init(utils::home(name), config); } Some(Commands::Run { name }) => { - let side_dir = home(name); - let (mut bft_crdt, keys) = list_transaction_crdt::new(side_dir); - websocket::start(keys, &mut bft_crdt).await; + let (crdt, websocket_client) = setup(name); + let side_node = &mut SideNode::new(websocket_client, crdt, name.to_owned()); + side_node.start().await; } None => println!("No command provided. Exiting. See --help for more information."), } } -fn home(name: &String) -> std::path::PathBuf { - let mut path = dirs::home_dir().unwrap(); - path.push(".side"); - path.push(name); - path +fn setup(name: &String) -> (BaseCrdt, WebSocketClient) { + let side_dir = utils::home(name); + let keys = keys::load_from_file(side_dir); + + let websocket_client = WebSocketClient::new(); + let crdt = BaseCrdt::::new(&keys); + + (crdt, websocket_client) } diff --git a/side-node/src/node.rs b/side-node/src/node.rs new file mode 100644 index 0000000..c2e1217 --- /dev/null +++ b/side-node/src/node.rs @@ -0,0 +1,31 @@ +use bft_json_crdt::json_crdt::BaseCrdt; +use fastcrypto::ed25519::Ed25519KeyPair; + +use crate::{keys, list_transaction_crdt::TransactionList, utils, websocket::WebSocketClient}; + +pub(crate) struct SideNode { + crdt: BaseCrdt, + keys: Ed25519KeyPair, + websocket_client: WebSocketClient, +} + +impl SideNode { + pub(crate) fn new( + websocket_client: WebSocketClient, + crdt: BaseCrdt, + name: String, + ) -> Self { + let side_dir = utils::home(&name); + let keys = keys::load_from_file(side_dir); + + Self { + crdt, + keys, + websocket_client, + } + } + + pub(crate) async fn start(&mut self) { + self.websocket_client.start().await; + } +} diff --git a/side-node/src/utils.rs b/side-node/src/utils.rs index 652e53f..ef94e2b 100644 --- a/side-node/src/utils.rs +++ b/side-node/src/utils.rs @@ -3,7 +3,7 @@ use std::path::PathBuf; pub(crate) const KEY_FILE: &str = "keys.pem"; pub(crate) const CONFIG_FILE: &str = "config.toml"; -/// Returns the path to the key file for this host OS. +/// Returns the path to the key file and config for this host OS. pub(crate) fn side_paths(prefix: PathBuf) -> (PathBuf, PathBuf) { let mut key_path = prefix.clone(); key_path.push(KEY_FILE); @@ -13,3 +13,10 @@ pub(crate) fn side_paths(prefix: PathBuf) -> (PathBuf, PathBuf) { (key_path, config_path) } + +pub(crate) fn home(name: &String) -> std::path::PathBuf { + let mut path = dirs::home_dir().unwrap(); + path.push(".side"); + path.push(name); + path +} diff --git a/side-node/src/websocket/mod.rs b/side-node/src/websocket/mod.rs index e0fe647..5968597 100644 --- a/side-node/src/websocket/mod.rs +++ b/side-node/src/websocket/mod.rs @@ -1,28 +1,47 @@ -/* - -loop { - let author = general_purpose::STANDARD.encode(&incoming_operation.author()); - bft_crdt.apply(incoming_operation.clone()); -} - -*/ - use async_trait::async_trait; -use bft_json_crdt::json_crdt::BaseCrdt; use ezsockets::ClientConfig; -use fastcrypto::ed25519::Ed25519KeyPair; use std::io::BufRead; -use crate::list_transaction_crdt::{self, CrdtList}; +pub(crate) struct WebSocketClient {} -struct Client {} +impl WebSocketClient { + pub(crate) fn new() -> Self { + Self {} + } + + /// Start the websocket client + pub(crate) async fn start(&mut self) { + tracing_subscriber::fmt::init(); + let config = ClientConfig::new("ws://localhost:8080/websocket"); + let (handle, future) = ezsockets::connect(|_client| WebSocketClient {}, config).await; + tokio::spawn(async move { + future.await.unwrap(); + }); + let stdin = std::io::stdin(); + let lines = stdin.lock().lines(); + for line in lines { + let line = line.unwrap(); + let signed_op = if let "exit" = line.as_str() { + break; + } else { + // list_transaction_crdt::create(bft_crdt, &keys) + }; + tracing::info!("sending {:?}", signed_op); + let json = serde_json::to_string(&signed_op).unwrap(); + handle.text(json).unwrap(); + } + } +} #[async_trait] -impl ezsockets::ClientExt for Client { +impl ezsockets::ClientExt for WebSocketClient { type Call = (); async fn on_text(&mut self, text: String) -> Result<(), ezsockets::Error> { tracing::info!("received message: {text}"); + // let incoming: bft_json_crdt::json_crdt::SignedOp = serde_json::from_str(&text).unwrap(); + // let author = base64::engine::general_purpose::STANDARD.encode(&incoming.author()); + // self.bft_crdt.apply(incoming.clone()); Ok(()) } @@ -37,24 +56,4 @@ impl ezsockets::ClientExt for Client { } } -pub(crate) async fn start(keys: Ed25519KeyPair, bft_crdt: &mut BaseCrdt) { - tracing_subscriber::fmt::init(); - let config = ClientConfig::new("ws://localhost:8080/websocket"); - let (handle, future) = ezsockets::connect(|_client| Client {}, config).await; - tokio::spawn(async move { - future.await.unwrap(); - }); - let stdin = std::io::stdin(); - let lines = stdin.lock().lines(); - for line in lines { - let line = line.unwrap(); - let signed_op = if let "exit" = line.as_str() { - break; - } else { - list_transaction_crdt::create(bft_crdt, &keys) - }; - tracing::info!("sending {:?}", signed_op); - let json = serde_json::to_string(&signed_op).unwrap(); - handle.text(json).unwrap(); - } -} +// pub(crate) async fn start(self, keys: Ed25519KeyPair, bft_crdt: &mut BaseCrdt) {}