From a31e94f843c401d4766050037ec9cbd474e508dc Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Mon, 30 Oct 2023 16:25:04 -0700 Subject: [PATCH 01/24] parse command-line args using clap --- Cargo.lock | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 3 +- src/main.rs | 20 +++------- src/types.rs | 14 +++++++ 4 files changed, 129 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c9e8c7fe..f0812b96 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -112,6 +112,54 @@ dependencies = [ "libc", ] +[[package]] +name = "anstream" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" + +[[package]] +name = "anstyle-parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" +dependencies = [ + "anstyle", + "windows-sys", +] + [[package]] name = "anyhow" version = "1.0.75" @@ -560,6 +608,46 @@ dependencies = [ "rlp", ] +[[package]] +name = "clap" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim 0.10.0", +] + +[[package]] +name = "clap_derive" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.32", +] + +[[package]] +name = "clap_lex" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" + [[package]] name = "coins-bip32" version = "0.8.7" @@ -612,6 +700,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + [[package]] name = "const-hex" version = "1.8.0" @@ -930,7 +1024,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim", + "strsim 0.9.3", "syn 1.0.109", ] @@ -4266,6 +4360,12 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "strum" version = "0.25.0" @@ -4846,6 +4946,7 @@ dependencies = [ "chacha20poly1305", "chrono", "cita_trie", + "clap", "crossterm", "digest 0.10.7", "dotenv", @@ -4908,6 +5009,12 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + [[package]] name = "uuid" version = "0.8.2" diff --git a/Cargo.toml b/Cargo.toml index 733d3121..4279b304 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ cap-std = "2.0.0" chacha20poly1305 = "0.10.1" chrono = "0.4.31" cita_trie = "4.0.0" +clap = { version = "4.4", features = ["derive"] } crossterm = { version = "0.26.1", features = ["event-stream", "bracketed-paste"] } digest = "0.10" dotenv = "0.15.0" @@ -65,4 +66,4 @@ uuid = { version = "1.1.2", features = ["serde", "v4"] } warp = "0.3.5" wasmtime = "12.0.1" wasmtime-wasi = "12.0.1" -zip = "0.6" \ No newline at end of file +zip = "0.6" diff --git a/src/main.rs b/src/main.rs index 8d101ad9..aef27354 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ use anyhow::Result; +use clap::Parser; use dotenv; use ethers::prelude::namehash; use std::env; @@ -42,26 +43,15 @@ async fn main() { // For use with https://github.com/tokio-rs/console // console_subscriber::init(); - // DEMO ONLY: remove all CLI arguments - let args: Vec = env::args().collect(); - let home_directory_path = &args[1]; - // let home_directory_path = "home"; - // create home directory if it does not already exist + let args = types::Args::parse(); + + let home_directory_path = &args.home; if let Err(e) = fs::create_dir_all(home_directory_path).await { panic!("failed to create home directory: {:?}", e); } // read PKI from websocket endpoint served by public RPC // if you get rate-limited or something, pass in your own RPC as a boot argument - let mut rpc_url = "".to_string(); - - for (i, arg) in args.iter().enumerate() { - if arg == "--rpc" { - // Check if the next argument exists and is not another flag - if i + 1 < args.len() && !args[i + 1].starts_with('-') { - rpc_url = args[i + 1].clone(); - } - } - } + let rpc_url = args.rpc; // kernel receives system messages via this channel, all other modules send messages let (kernel_message_sender, kernel_message_receiver): (MessageSender, MessageReceiver) = diff --git a/src/types.rs b/src/types.rs index 7da38326..6ae63e95 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,4 +1,5 @@ use crate::kernel::component::uq_process::types as wit; +use clap::Parser; use ring::signature; use serde::{Deserialize, Serialize}; use std::{ @@ -19,6 +20,19 @@ lazy_static::lazy_static! { pub static ref VFS_PROCESS_ID: ProcessId = ProcessId::new(Some("vfs"), "sys", "uqbar"); } +#[derive(Parser, Debug)] +/// Uqbar: your p2p personal node integrating cryptocurrency and AI +#[command(author, version, about, long_about = None)] +pub struct Args { + /// Home directory + #[arg(short, long)] + pub home: String, + + /// Ethereum RPC endpoint + #[arg(short, long, default_value_t = String::new())] + pub rpc: String, +} + // // internal message pipes between kernel and runtime modules // From a46569ea2707ccafb391ba00338cc498ac422c19 Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Mon, 30 Oct 2023 17:33:50 -0700 Subject: [PATCH 02/24] add --password flag (for indirect nodes only) --- README.md | 2 +- src/main.rs | 101 ++++++++++++++++++++++++++++++++------------------- src/types.rs | 4 ++ 3 files changed, 69 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 570e0934..6d76cc9f 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ If you do not receive QNS updates in terminal, it's a sign that the default publ Also, make sure not to use the same home directory for two nodes at once! You can use any name for the home directory. ```bash -cargo +nightly run --release home --rpc wss://eth-sepolia.g.alchemy.com/v2/ +cargo +nightly run --release -- --home home --rpc wss://eth-sepolia.g.alchemy.com/v2/ ``` On boot you will be prompted to navigate to `localhost:8080`. Make sure your eth wallet is connected to the Sepolia test network. Login should be very straightforward, just submit the transactions and follow the flow. diff --git a/src/main.rs b/src/main.rs index aef27354..f97b52ff 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ use anyhow::Result; use clap::Parser; use dotenv; use ethers::prelude::namehash; +use ring::signature::KeyPair; use std::env; use std::sync::Arc; use tokio::sync::{mpsc, oneshot}; @@ -161,46 +162,73 @@ async fn main() { } }; - // check if we have keys saved on disk, encrypted - // if so, prompt user for "password" to decrypt with - - // once password is received, use to decrypt local keys file, - // and pass the keys into boot process as is done in registration. - - // NOTE: when we log in, we MUST check the PKI to make sure our - // information matches what we think it should be. this includes - // username, networking key, and routing info. - // if any do not match, we should prompt user to create a "transaction" - // that updates their PKI info on-chain. let http_server_port = http_server::find_open_port(8080).await.unwrap(); - let (kill_tx, kill_rx) = oneshot::channel::(); + let (our, decoded_keyfile) = match args.password { + Some(password) => { + match fs::read(format!("{}/.keys", home_directory_path)).await { + Err(e) => panic!("could not read keyfile: {}", e), + Ok(keyfile) => { + match keygen::decode_keyfile(keyfile, &password) { + Err(e) => panic!("could not decode keyfile: {}", e), + Ok(decoded_keyfile) => { + let our = Identity { + name: decoded_keyfile.username.clone(), + networking_key: format!("0x{}", hex::encode(decoded_keyfile.networking_keypair.public_key().as_ref())), + ws_routing: None, // TODO + allowed_routers: decoded_keyfile.routers.clone(), + }; + (our, decoded_keyfile) + }, + } + }, + } + }, + None => { + // check if we have keys saved on disk, encrypted + // if so, prompt user for "password" to decrypt with - let disk_keyfile = match fs::read(format!("{}/.keys", home_directory_path)).await { - Ok(keyfile) => keyfile, - Err(_) => Vec::new(), + // once password is received, use to decrypt local keys file, + // and pass the keys into boot process as is done in registration. + + // NOTE: when we log in, we MUST check the PKI to make sure our + // information matches what we think it should be. this includes + // username, networking key, and routing info. + // if any do not match, we should prompt user to create a "transaction" + // that updates their PKI info on-chain. + let (kill_tx, kill_rx) = oneshot::channel::(); + + let disk_keyfile = match fs::read(format!("{}/.keys", home_directory_path)).await { + Ok(keyfile) => keyfile, + Err(_) => Vec::new(), + }; + + let (tx, mut rx) = mpsc::channel::<(Identity, Keyfile, Vec)>(1); + let (our, decoded_keyfile, encoded_keyfile) = tokio::select! { + _ = register::register(tx, kill_rx, our_ip.to_string(), http_server_port, disk_keyfile) + => panic!("registration failed"), + (our, decoded_keyfile, encoded_keyfile) = async { + while let Some(fin) = rx.recv().await { return fin } + panic!("registration failed") + } => (our, decoded_keyfile, encoded_keyfile), + }; + + println!( + "saving encrypted networking keys to {}/.keys", + home_directory_path + ); + + fs::write(format!("{}/.keys", home_directory_path), encoded_keyfile) + .await + .unwrap(); + + println!("registration complete!"); + + let _ = kill_tx.send(true); + + (our, decoded_keyfile) + }, }; - let (tx, mut rx) = mpsc::channel::<(Identity, Keyfile, Vec)>(1); - let (our, decoded_keyfile, encoded_keyfile) = tokio::select! { - _ = register::register(tx, kill_rx, our_ip.to_string(), http_server_port, disk_keyfile) - => panic!("registration failed"), - (our, decoded_keyfile, encoded_keyfile) = async { - while let Some(fin) = rx.recv().await { return fin } - panic!("registration failed") - } => (our, decoded_keyfile, encoded_keyfile), - }; - - println!( - "saving encrypted networking keys to {}/.keys", - home_directory_path - ); - - fs::write(format!("{}/.keys", home_directory_path), encoded_keyfile) - .await - .unwrap(); - - println!("registration complete!"); - let (kernel_process_map, manifest, vfs_messages) = filesystem::load_fs( our.name.clone(), home_directory_path.clone(), @@ -210,7 +238,6 @@ async fn main() { .await .expect("fs load failed!"); - let _ = kill_tx.send(true); let _ = print_sender .send(Printout { verbosity: 0, diff --git a/src/types.rs b/src/types.rs index 6ae63e95..c8d320da 100644 --- a/src/types.rs +++ b/src/types.rs @@ -31,6 +31,10 @@ pub struct Args { /// Ethereum RPC endpoint #[arg(short, long, default_value_t = String::new())] pub rpc: String, + + /// Networking password + #[arg(short, long, value_parser)] + pub password: Option, } // From 16489624ce5506f6e303e100e907eba5c51f3c19 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 31 Oct 2023 00:34:17 +0000 Subject: [PATCH 03/24] Format Rust code using rustfmt --- src/main.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main.rs b/src/main.rs index f97b52ff..4614f388 100644 --- a/src/main.rs +++ b/src/main.rs @@ -173,16 +173,21 @@ async fn main() { Ok(decoded_keyfile) => { let our = Identity { name: decoded_keyfile.username.clone(), - networking_key: format!("0x{}", hex::encode(decoded_keyfile.networking_keypair.public_key().as_ref())), - ws_routing: None, // TODO + networking_key: format!( + "0x{}", + hex::encode( + decoded_keyfile.networking_keypair.public_key().as_ref() + ) + ), + ws_routing: None, // TODO allowed_routers: decoded_keyfile.routers.clone(), }; (our, decoded_keyfile) - }, + } } - }, + } } - }, + } None => { // check if we have keys saved on disk, encrypted // if so, prompt user for "password" to decrypt with @@ -226,7 +231,7 @@ async fn main() { let _ = kill_tx.send(true); (our, decoded_keyfile) - }, + } }; let (kernel_process_map, manifest, vfs_messages) = filesystem::load_fs( From 8fdb46dddba52d9f5ef52a4acf23e6422598225d Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Wed, 1 Nov 2023 14:42:37 -0700 Subject: [PATCH 04/24] add --port flag (defaults to 8080) --- src/main.rs | 2 +- src/types.rs | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 4614f388..94d8e113 100644 --- a/src/main.rs +++ b/src/main.rs @@ -162,7 +162,7 @@ async fn main() { } }; - let http_server_port = http_server::find_open_port(8080).await.unwrap(); + let http_server_port = http_server::find_open_port(args.port).await.unwrap(); let (our, decoded_keyfile) = match args.password { Some(password) => { match fs::read(format!("{}/.keys", home_directory_path)).await { diff --git a/src/types.rs b/src/types.rs index c8d320da..688d744c 100644 --- a/src/types.rs +++ b/src/types.rs @@ -32,6 +32,10 @@ pub struct Args { #[arg(short, long, default_value_t = String::new())] pub rpc: String, + /// First port to try binding + #[arg(long, default_value_t = 8080)] + pub port: u16, + /// Networking password #[arg(short, long, value_parser)] pub password: Option, From 0afdc79f46974e3ed447cddd0825d232899e78d4 Mon Sep 17 00:00:00 2001 From: bitful-pannul <109035169+bitful-pannul@users.noreply.github.com> Date: Thu, 2 Nov 2023 15:19:45 +0000 Subject: [PATCH 05/24] vfs clean (#38) Co-authored-by: hosted-fornet --- src/types.rs | 9 + src/vfs.rs | 905 +++++++++++++++++++++++---------------------------- 2 files changed, 425 insertions(+), 489 deletions(-) diff --git a/src/types.rs b/src/types.rs index 688d744c..c5b29600 100644 --- a/src/types.rs +++ b/src/types.rs @@ -611,6 +611,7 @@ pub enum VfsAction { full_path: String, offset: u64, }, + Append(String), SetSize { full_path: String, size: u64, @@ -657,20 +658,28 @@ pub enum VfsResponse { #[derive(Debug, Serialize, Deserialize)] pub enum VfsError { + BadJson, + BadPayload, BadDriveName, BadDescriptor, NoCap, EntryNotFound, + PersistError, + InternalError, // String } #[allow(dead_code)] impl VfsError { pub fn kind(&self) -> &str { match *self { + VfsError::BadJson => "BadJson", + VfsError::BadPayload => "BadPayload", VfsError::BadDriveName => "BadDriveName", VfsError::BadDescriptor => "BadDescriptor", VfsError::NoCap => "NoCap", VfsError::EntryNotFound => "EntryNotFound", + VfsError::PersistError => "PersistError", + VfsError::InternalError => "InternalError", } } } diff --git a/src/vfs.rs b/src/vfs.rs index f0780b8d..a77219f5 100644 --- a/src/vfs.rs +++ b/src/vfs.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; use std::collections::{HashMap, HashSet, VecDeque}; use std::io::prelude::*; use std::sync::Arc; -use tokio::sync::Mutex; +use tokio::sync::{Mutex, MutexGuard}; use crate::types::*; @@ -34,15 +34,15 @@ type DriveToQueue = Arc>>; #[derive(Clone, Debug, Deserialize, Serialize)] struct Entry { name: String, - full_path: String, // full_path, ending with `/` for dir + full_path: String, entry_type: EntryType, // ... // general metadata? } + #[derive(Clone, Debug, Deserialize, Serialize)] enum EntryType { Dir { parent: Key, children: HashSet }, File { parent: Key }, // hash could be generalized to `location` if we want to be able to point at, e.g., remote files - // ... // symlinks? } impl Vfs { @@ -70,31 +70,98 @@ impl Vfs { } } -fn make_dir_name(full_path: &str) -> (String, String) { - if full_path == "/" { - return ("/".into(), "".into()); // root case - } - let mut split_path: Vec<&str> = full_path.split("/").collect(); - let _ = split_path.pop(); - let name = format!("{}/", split_path.pop().unwrap()); - let path = split_path.join("/"); - let path = if path == "" { - "/".into() - } else { - format!("{}/", path) - }; - (name, path) +fn clean_path(path: &str) -> String { + let cleaned = path.trim_start_matches('/').trim_end_matches('/'); + format!("/{}", cleaned) } -fn make_file_name(full_path: &str) -> (String, String) { - let mut split_path: Vec<&str> = full_path.split("/").collect(); - let name = split_path.pop().unwrap_or("").to_string(); - let path = if split_path.is_empty() { - String::new() +fn get_parent_path(path: &str) -> String { + let mut split_path: Vec<&str> = path.split("/").collect(); + split_path.pop(); + let parent_path = split_path.join("/"); + if parent_path.is_empty() { + "/".to_string() } else { - format!("{}/", split_path.join("/")) + parent_path + } +} + +#[async_recursion::async_recursion] +async fn create_entry(vfs: &mut MutexGuard, path: &str, key: Key) -> Result { + if let Some(existing_key) = vfs.path_to_key.get(path) { + return Ok(existing_key.clone()); + } + + let parent_path = get_parent_path(path); + let parent_key = create_entry(vfs, &parent_path, Key::Dir { id: rand::random() }).await?; + + let entry_type = match key { + Key::Dir { id: _ } => EntryType::Dir { + parent: parent_key.clone(), + children: HashSet::new(), + }, + Key::File { id: _ } => EntryType::File { + parent: parent_key.clone(), + }, }; - (name, path) + let entry = Entry { + name: path.split("/").last().unwrap().to_string(), + full_path: path.to_string(), + entry_type: entry_type, + }; + vfs.key_to_entry.insert(key.clone(), entry); + vfs.path_to_key.insert(path.to_string(), key.clone()); + + if let Some(parent_entry) = vfs.key_to_entry.get_mut(&parent_key) { + if let EntryType::Dir { children, .. } = &mut parent_entry.entry_type { + children.insert(key.clone()); + } + } + + Ok(key) +} + +#[async_recursion::async_recursion] +async fn rename_entry( + vfs: Arc>, + old_path: &str, + new_path: &str, +) -> Result<(), VfsError> { + let children = { + let mut vfs = vfs.lock().await; + let key = match vfs.path_to_key.remove(old_path) { + Some(key) => key, + None => return Err(VfsError::EntryNotFound), + }; + let entry = match vfs.key_to_entry.get_mut(&key) { + Some(entry) => entry, + None => return Err(VfsError::EntryNotFound), + }; + entry.name = new_path.split("/").last().unwrap().to_string(); + entry.full_path = new_path.to_string(); + + let children = if let EntryType::Dir { children, .. } = &entry.entry_type { + children.clone() + } else { + HashSet::new() + }; + + vfs.path_to_key.insert(new_path.to_string(), key); + children + }; + + // recursively update the paths of the children + for child_key in children { + let child_entry = { + let vfs = vfs.lock().await; + vfs.key_to_entry.get(&child_key).unwrap().clone() + }; + let old_child_path = child_entry.full_path.clone(); + let new_child_path = old_child_path.replace(old_path, new_path); + rename_entry(vfs.clone(), &old_child_path, &new_child_path).await?; + } + + Ok(()) } fn make_error_message( @@ -114,7 +181,7 @@ fn make_error_message( message: Message::Response(( Response { inherit: false, - ipc: serde_json::to_vec(&VfsResponse::Err(error)).unwrap(), // TODO: handle error? + ipc: serde_json::to_vec(&VfsResponse::Err(error)).unwrap(), metadata: None, }, None, @@ -177,18 +244,23 @@ async fn persist_state( send_to_persist: &tokio::sync::mpsc::Sender, recv_response: &mut MessageReceiver, id: u64, -) { - send_to_persist.send(id).await.unwrap(); - let persist_response = recv_response.recv().await.unwrap(); +) -> Result<(), VfsError> { + send_to_persist + .send(id) + .await + .map_err(|_| VfsError::PersistError)?; + let persist_response = recv_response.recv().await.ok_or(VfsError::PersistError)?; let KernelMessage { message, .. } = persist_response; let Message::Response((Response { ipc, .. }, None)) = message else { - panic!(""); - }; - let Ok(FsResponse::SetState) = - serde_json::from_slice::>(&ipc).unwrap() - else { - panic!(""); + return Err(VfsError::PersistError); }; + + let response = serde_json::from_slice::>(&ipc) + .map_err(|_| VfsError::PersistError)?; + match response { + Ok(FsResponse::SetState) => Ok(()), + _ => Err(VfsError::PersistError), + } } async fn load_state_from_reboot( @@ -235,7 +307,7 @@ async fn load_state_from_reboot( return (); }; let Some(payload) = payload else { - panic!(""); + return (); }; bytes_to_state(&payload.bytes, drive_to_vfs); } @@ -248,7 +320,6 @@ pub async fn vfs( send_to_caps_oracle: CapMessageSender, vfs_messages: Vec, ) -> anyhow::Result<()> { - println!("vfs: begin\r"); let mut drive_to_vfs: DriveToVfs = HashMap::new(); let drive_to_queue: DriveToQueue = Arc::new(Mutex::new(HashMap::new())); let mut response_router: ResponseRouter = HashMap::new(); @@ -521,7 +592,6 @@ pub async fn vfs( } } -// TODO: error handling: send error messages to caller async fn handle_request( our_node: String, id: u64, @@ -545,6 +615,7 @@ async fn handle_request( | VfsAction::Rename { .. } | VfsAction::Delete { .. } | VfsAction::WriteOffset { .. } + | VfsAction::Append { .. } | VfsAction::SetSize { .. } => { let _ = send_to_caps_oracle .send(CapMessage::Has { @@ -597,7 +668,7 @@ async fn handle_request( return Err(VfsError::NoCap); } } - _ => {} // New + VfsAction::New { .. } => {} } let (ipc, bytes) = match_request( @@ -616,19 +687,20 @@ async fn handle_request( ) .await?; - // TODO: properly handle rsvp - if expects_response.is_some() { + if let Some(target) = rsvp.or_else(|| { + expects_response.map(|_| Address { + node: our_node.clone(), + process: source.process.clone(), + }) + }) { let response = KernelMessage { id, source: Address { node: our_node.clone(), process: VFS_PROCESS_ID.clone(), }, - target: Address { - node: our_node.clone(), - process: source.process.clone(), - }, - rsvp, + target, + rsvp: None, message: Message::Response(( Response { inherit: false, @@ -648,6 +720,17 @@ async fn handle_request( }; let _ = send_to_loop.send(response).await; + } else { + let _ = send_to_terminal + .send(Printout { + verbosity: 1, + content: format!( + "vfs: not sending response: {:?}", + serde_json::from_slice::(&ipc) + ), + }) + .await + .unwrap(); } Ok(()) @@ -682,35 +765,17 @@ async fn match_request( .unwrap(); let _ = recv_cap_bool.await.unwrap(); } - persist_state(send_to_persist, &mut recv_response, id).await; + persist_state(send_to_persist, &mut recv_response, id).await?; (serde_json::to_vec(&VfsResponse::Ok).unwrap(), None) } VfsAction::Add { - full_path, + mut full_path, entry_type, } => { match entry_type { AddEntryType::Dir => { - if let Some(last_char) = full_path.chars().last() { - if last_char != '/' { - // TODO: panic or correct & notify? - // elsewhere we panic - // format!("{}/", full_path) - send_to_terminal - .send(Printout { - verbosity: 0, - content: format!( - "vfs: cannot add dir without trailing `/`: {}", - full_path - ), - }) - .await - .unwrap(); - panic!(""); - }; - } else { - panic!("empty path"); - }; + full_path = clean_path(&full_path); + let mut vfs = vfs.lock().await; if vfs.path_to_key.contains_key(&full_path) { send_to_terminal @@ -720,58 +785,18 @@ async fn match_request( }) .await .unwrap(); - panic!(""); // TODO: error? + return Ok((serde_json::to_vec(&VfsResponse::Ok).unwrap(), None)); }; - let (name, parent_path) = make_dir_name(&full_path); - let Some(parent_key) = vfs.path_to_key.remove(&parent_path) else { - panic!("fp, pp: {}, {}", full_path, parent_path); - }; - let Some(mut parent_entry) = vfs.key_to_entry.remove(&parent_key) else { - panic!(""); - }; - let EntryType::Dir { - children: ref mut parent_children, - .. - } = parent_entry.entry_type - else { - panic!(""); - }; - let key = Key::Dir { id: rand::random() }; - vfs.key_to_entry.insert( - key.clone(), - Entry { - name, - full_path: full_path.clone(), - entry_type: EntryType::Dir { - parent: parent_key.clone(), - children: HashSet::new(), - }, - }, - ); - parent_children.insert(key.clone()); - vfs.path_to_key.insert(parent_path, parent_key.clone()); - vfs.key_to_entry.insert(parent_key, parent_entry); - vfs.path_to_key.insert(full_path.clone(), key.clone()); + match create_entry(&mut vfs, &full_path, Key::Dir { id: rand::random() }).await + { + Ok(_) => {} + Err(e) => { + return Err(e); + } + } } AddEntryType::NewFile => { - if let Some(last_char) = full_path.chars().last() { - if last_char == '/' { - send_to_terminal - .send(Printout { - verbosity: 0, - content: format!( - "vfs: file path cannot end with `/`: {}", - full_path, - ), - }) - .await - .unwrap(); - panic!(""); - } - } else { - panic!("empty path"); - }; - + full_path = clean_path(&full_path); let hash = { let mut vfs = vfs.lock().await; if !vfs.path_to_key.contains_key(&full_path) { @@ -788,7 +813,7 @@ async fn match_request( None => None, Some(key) => { let Key::File { id: hash } = key else { - panic!(""); + return Err(VfsError::InternalError); }; Some(hash) } @@ -822,65 +847,27 @@ async fn match_request( let write_response = recv_response.recv().await.unwrap(); let KernelMessage { message, .. } = write_response; let Message::Response((Response { ipc, .. }, None)) = message else { - panic!(""); + return Err(VfsError::InternalError); }; + let Ok(FsResponse::Write(hash)) = serde_json::from_slice::>(&ipc).unwrap() else { - panic!(""); + return Err(VfsError::InternalError); }; - let (name, parent_path) = make_file_name(&full_path); - let mut vfs = vfs.lock().await; - let Some(parent_key) = vfs.path_to_key.remove(&parent_path) else { - panic!(""); - }; - - let Some(mut parent_entry) = vfs.key_to_entry.remove(&parent_key) else { - panic!(""); - }; - - let EntryType::Dir { - children: ref mut parent_children, - .. - } = parent_entry.entry_type - else { - panic!(""); - }; - let key = Key::File { id: hash }; - vfs.key_to_entry.insert( - key.clone(), - Entry { - name, - full_path: full_path.clone(), - entry_type: EntryType::File { - parent: parent_key.clone(), - }, - }, - ); - parent_children.insert(key.clone()); - vfs.path_to_key.insert(parent_path, parent_key.clone()); - vfs.key_to_entry.insert(parent_key, parent_entry); - vfs.path_to_key.insert(full_path.clone(), key.clone()); + match create_entry(&mut vfs.lock().await, &full_path, Key::File { id: hash }) + .await + { + Ok(_) => {} + Err(e) => { + return Err(e); + } + } } AddEntryType::ExistingFile { hash } => { - if let Some(last_char) = full_path.chars().last() { - if last_char == '/' { - send_to_terminal - .send(Printout { - verbosity: 0, - content: format!( - "vfs: file path cannot end with `/`: {}", - full_path, - ), - }) - .await - .unwrap(); - panic!(""); - } - } else { - panic!("empty path"); - }; + full_path = clean_path(&full_path); + let mut vfs = vfs.lock().await; if vfs.path_to_key.contains_key(&full_path) { send_to_terminal @@ -891,54 +878,32 @@ async fn match_request( .await .unwrap(); let Some(old_key) = vfs.path_to_key.remove(&full_path) else { - panic!("no old key"); + println!("no old key"); + return Err(VfsError::InternalError); }; vfs.key_to_entry.remove(&old_key); }; - let (name, parent_path) = make_file_name(&full_path); - let Some(parent_key) = vfs.path_to_key.remove(&parent_path) else { - panic!(""); - }; - let Some(mut parent_entry) = vfs.key_to_entry.remove(&parent_key) else { - panic!(""); - }; - let EntryType::Dir { - children: ref mut parent_children, - .. - } = parent_entry.entry_type - else { - panic!(""); - }; - let key = Key::File { id: hash }; - vfs.key_to_entry.insert( - key.clone(), - Entry { - name, - full_path: full_path.clone(), - entry_type: EntryType::File { - parent: parent_key.clone(), - }, - }, - ); - parent_children.insert(key.clone()); - vfs.path_to_key.insert(parent_path, parent_key.clone()); - vfs.key_to_entry.insert(parent_key, parent_entry); - vfs.path_to_key.insert(full_path.clone(), key.clone()); + match create_entry(&mut vfs, &full_path, Key::File { id: hash }).await { + Ok(_) => {} + Err(e) => { + return Err(e); + } + } } AddEntryType::ZipArchive => { let Some(payload) = payload else { - panic!(""); + return Err(VfsError::BadPayload); }; let Some(mime) = payload.mime else { - panic!(""); + return Err(VfsError::BadPayload); }; if "application/zip" != mime { - panic!(""); + return Err(VfsError::BadPayload); } let file = std::io::Cursor::new(&payload.bytes); let mut zip = match zip::ZipArchive::new(file) { Ok(f) => f, - Err(e) => panic!("vfs: zip error: {:?}", e), + Err(_) => return Err(VfsError::InternalError), }; // loop through items in archive; recursively add to root @@ -974,7 +939,7 @@ async fn match_request( None => None, Some(key) => { let Key::File { id: hash } = key else { - panic!(""); + return Err(VfsError::InternalError); }; Some(*hash) } @@ -1016,123 +981,60 @@ async fn match_request( }; let KernelMessage { message, .. } = write_response; let Message::Response((Response { ipc, .. }, None)) = message else { - panic!("") + return Err(VfsError::InternalError); }; + let Ok(FsResponse::Write(hash)) = serde_json::from_slice::>(&ipc) .unwrap() else { - panic!(""); + return Err(VfsError::InternalError); }; - let (name, parent_path) = make_file_name(&full_path); - let mut vfs = vfs.lock().await; - let Some(parent_key) = vfs.path_to_key.remove(&parent_path) else { - panic!(""); - }; - let Some(mut parent_entry) = vfs.key_to_entry.remove(&parent_key) - else { - panic!(""); - }; - let EntryType::Dir { - children: ref mut parent_children, - .. - } = parent_entry.entry_type - else { - panic!(""); - }; - let key = Key::File { id: hash }; - vfs.key_to_entry.insert( - key.clone(), - Entry { - name, - full_path: full_path.clone(), - entry_type: EntryType::File { - parent: parent_key.clone(), - }, - }, - ); - parent_children.insert(key.clone()); - vfs.path_to_key.insert(parent_path, parent_key.clone()); - vfs.key_to_entry.insert(parent_key, parent_entry); - vfs.path_to_key.insert(full_path.clone(), key.clone()); + match create_entry( + &mut vfs.lock().await, + &full_path, + Key::File { id: hash }, + ) + .await + { + Ok(_) => {} + Err(e) => { + return Err(e); + } + } } else if is_dir { - panic!("vfs: zip dir not yet implemented"); + println!("vfs: zip dir not yet implemented"); + return Err(VfsError::InternalError); } else { - panic!("vfs: zip with non-file non-dir"); + println!("vfs: zip with non-file non-dir"); + return Err(VfsError::InternalError); }; } } } - persist_state(send_to_persist, &mut recv_response, id).await; + persist_state(send_to_persist, &mut recv_response, id).await?; (serde_json::to_vec(&VfsResponse::Ok).unwrap(), None) } VfsAction::Rename { - full_path, - new_full_path, + mut full_path, + mut new_full_path, } => { - let mut vfs = vfs.lock().await; - let Some(key) = vfs.path_to_key.remove(&full_path) else { - send_to_terminal - .send(Printout { - verbosity: 0, - content: format!("vfs: can't rename: nonexistent file {}", full_path), - }) - .await - .unwrap(); - return Err(VfsError::EntryNotFound); - }; - let Some(mut entry) = vfs.key_to_entry.remove(&key) else { - send_to_terminal - .send(Printout { - verbosity: 0, - content: format!("vfs: can't rename: nonexistent file {}", full_path), - }) - .await - .unwrap(); - return Err(VfsError::EntryNotFound); - }; - match entry.entry_type { - EntryType::Dir { .. } => { - if vfs.path_to_key.contains_key(&new_full_path) { - send_to_terminal - .send(Printout { - verbosity: 0, - content: format!("vfs: not overwriting dir {}", new_full_path), - }) - .await - .unwrap(); - vfs.path_to_key.insert(full_path, key); - panic!(""); // TODO: error? - }; - let (name, _) = make_dir_name(&new_full_path); - entry.name = name; - entry.full_path = new_full_path.clone(); - vfs.path_to_key.insert(new_full_path.clone(), key.clone()); - vfs.key_to_entry.insert(key, entry); - // TODO: recursively apply path update to all children - // update_child_paths(full_path, new_full_path, children); - } - EntryType::File { parent: _ } => { - if vfs.path_to_key.contains_key(&new_full_path) { - let _ = send_to_terminal - .send(Printout { - verbosity: 1, - content: format!("vfs: overwriting file {}", new_full_path), - }) - .await; - }; - let (name, _) = make_file_name(&new_full_path); - entry.name = name; - entry.full_path = new_full_path.clone(); - vfs.path_to_key.insert(new_full_path.clone(), key.clone()); - vfs.key_to_entry.insert(key, entry); + full_path = clean_path(&full_path); + new_full_path = clean_path(&new_full_path); + match rename_entry(vfs, &full_path, &new_full_path).await { + Ok(_) => {} + Err(e) => { + return Err(e); } } - persist_state(send_to_persist, &mut recv_response, id).await; + + persist_state(send_to_persist, &mut recv_response, id).await?; (serde_json::to_vec(&VfsResponse::Ok).unwrap(), None) } - VfsAction::Delete(full_path) => { + VfsAction::Delete(mut full_path) => { + full_path = clean_path(&full_path); + let mut vfs = vfs.lock().await; let Some(key) = vfs.path_to_key.remove(&full_path) else { send_to_terminal @@ -1174,50 +1076,50 @@ async fn match_request( vfs.key_to_entry.insert(key.clone(), entry); } } - EntryType::File { parent } => { - match vfs.key_to_entry.get_mut(&parent) { - None => { - send_to_terminal - .send(Printout { - verbosity: 0, - content: format!( - "vfs: delete: unexpected file with no parent dir: {}", - full_path - ), - }) - .await - .unwrap(); - panic!(""); - } - Some(parent) => { - let EntryType::Dir { - parent: _, - ref mut children, - } = parent.entry_type - else { - panic!(""); - }; - // TODO: does this work? - children.remove(&key); - } + EntryType::File { parent } => match vfs.key_to_entry.get_mut(&parent) { + None => { + send_to_terminal + .send(Printout { + verbosity: 0, + content: format!( + "vfs: delete: unexpected file with no parent dir: {}", + full_path + ), + }) + .await + .unwrap(); + return Err(VfsError::InternalError); } - } + Some(parent) => { + let EntryType::Dir { + parent: _, + ref mut children, + } = parent.entry_type + else { + return Err(VfsError::InternalError); + }; + children.remove(&key); + } + }, } - persist_state(send_to_persist, &mut recv_response, id).await; + persist_state(send_to_persist, &mut recv_response, id).await?; (serde_json::to_vec(&VfsResponse::Ok).unwrap(), None) } - VfsAction::WriteOffset { full_path, offset } => { + VfsAction::WriteOffset { + mut full_path, + offset, + } => { + full_path = clean_path(&full_path); + let file_hash = { - let mut vfs = vfs.lock().await; - let Some(key) = vfs.path_to_key.remove(&full_path) else { + let vfs = vfs.lock().await; + let Some(key) = vfs.path_to_key.get(&full_path) else { return Err(VfsError::EntryNotFound); }; - let key2 = key.clone(); - let Key::File { id: file_hash } = key2 else { - panic!(""); // TODO + let Key::File { id: file_hash } = key else { + return Err(VfsError::InternalError); }; - vfs.path_to_key.insert(full_path.clone(), key); - file_hash + *file_hash }; let _ = send_to_loop .send(KernelMessage { @@ -1245,28 +1147,80 @@ async fn match_request( let write_response = recv_response.recv().await.unwrap(); let KernelMessage { message, .. } = write_response; let Message::Response((Response { ipc, .. }, None)) = message else { - panic!("") + return Err(VfsError::InternalError); }; + let Ok(FsResponse::Write(_)) = serde_json::from_slice::>(&ipc).unwrap() else { - panic!(""); + return Err(VfsError::InternalError); }; - persist_state(send_to_persist, &mut recv_response, id).await; (serde_json::to_vec(&VfsResponse::Ok).unwrap(), None) } - VfsAction::SetSize { full_path, size } => { + VfsAction::Append(mut full_path) => { + full_path = clean_path(&full_path); + let file_hash = { - let mut vfs = vfs.lock().await; - let Some(key) = vfs.path_to_key.remove(&full_path) else { + let vfs = vfs.lock().await; + let Some(key) = vfs.path_to_key.get(&full_path) else { return Err(VfsError::EntryNotFound); }; - let key2 = key.clone(); - let Key::File { id: file_hash } = key2 else { - panic!(""); // TODO + let Key::File { id: file_hash } = key else { + return Err(VfsError::InternalError); }; - vfs.path_to_key.insert(full_path.clone(), key); - file_hash + *file_hash + }; + let _ = send_to_loop + .send(KernelMessage { + id, + source: Address { + node: our_node.clone(), + process: VFS_PROCESS_ID.clone(), + }, + target: Address { + node: our_node.clone(), + process: FILESYSTEM_PROCESS_ID.clone(), + }, + rsvp: None, + message: Message::Request(Request { + inherit: true, + expects_response: Some(5), // TODO evaluate + ipc: serde_json::to_vec(&FsAction::Append(Some(file_hash))).unwrap(), + metadata: None, + }), + payload, + signed_capabilities: None, + }) + .await; + let write_response = recv_response.recv().await.unwrap(); + let KernelMessage { message, .. } = write_response; + let Message::Response((Response { ipc, .. }, None)) = message else { + return Err(VfsError::InternalError); + }; + + let Ok(FsResponse::Append(_)) = + serde_json::from_slice::>(&ipc).unwrap() + else { + return Err(VfsError::InternalError); + }; + persist_state(send_to_persist, &mut recv_response, id).await?; + (serde_json::to_vec(&VfsResponse::Ok).unwrap(), None) + } + VfsAction::SetSize { + mut full_path, + size, + } => { + full_path = clean_path(&full_path); + + let file_hash = { + let vfs = vfs.lock().await; + let Some(key) = vfs.path_to_key.get(&full_path) else { + return Err(VfsError::EntryNotFound); + }; + let Key::File { id: file_hash } = key else { + return Err(VfsError::InternalError); + }; + *file_hash }; let _ = send_to_loop @@ -1284,8 +1238,7 @@ async fn match_request( message: Message::Request(Request { inherit: true, expects_response: Some(15), - ipc: serde_json::to_vec(&FsAction::SetLength((file_hash.clone(), size))) - .unwrap(), + ipc: serde_json::to_vec(&FsAction::SetLength((file_hash, size))).unwrap(), metadata: None, }), payload: None, @@ -1295,15 +1248,17 @@ async fn match_request( let write_response = recv_response.recv().await.unwrap(); let KernelMessage { message, .. } = write_response; let Message::Response((Response { ipc, .. }, None)) = message else { - panic!("") + return Err(VfsError::InternalError); }; + let Ok(FsResponse::Length(length)) = serde_json::from_slice::>(&ipc).unwrap() else { - panic!(""); + return Err(VfsError::InternalError); + }; + if length != size { + return Err(VfsError::InternalError); }; - assert_eq!(size, length); - persist_state(send_to_persist, &mut recv_response, id).await; (serde_json::to_vec(&VfsResponse::Ok).unwrap(), None) } VfsAction::GetPath(hash) => { @@ -1333,143 +1288,112 @@ async fn match_request( .unwrap(); (ipc, None) } - VfsAction::GetEntry(ref full_path) => { - let (key, entry, paths) = { - let mut vfs = vfs.lock().await; - let key = vfs.path_to_key.remove(full_path); - match key { - None => (None, None, vec![]), - Some(key) => { - vfs.path_to_key.insert(full_path.clone(), key.clone()); - let entry = vfs.key_to_entry.remove(&key); - match entry { - None => (Some(key), None, vec![]), - Some(ref e) => { - vfs.key_to_entry.insert(key.clone(), e.clone()); - match e.entry_type { - EntryType::File { parent: _ } => (Some(key), entry, vec![]), - EntryType::Dir { - parent: _, - ref children, - } => { - let mut paths: Vec = Vec::new(); - for child in children { - let Some(child) = vfs.key_to_entry.get(&child) else { - send_to_terminal - .send(Printout { - verbosity: 0, - content: format!( - "vfs: child missing for: {}", - full_path - ), - }) - .await - .unwrap(); - continue; - }; - paths.push(child.full_path.clone()); - } - paths.sort(); - (Some(key), entry, paths) - } - } - } - } - } - } - }; + VfsAction::GetEntry(mut full_path) => { + full_path = clean_path(&full_path); + let vfs = vfs.lock().await; + let key = vfs.path_to_key.get(&full_path); match key { None => return Err(VfsError::EntryNotFound), - Some(key) => match entry { - None => return Err(VfsError::EntryNotFound), - Some(entry) => match entry.entry_type { - EntryType::Dir { - parent: _, - children: _, - } => ( - serde_json::to_vec(&VfsResponse::GetEntry { - is_file: false, - children: paths, - }) - .unwrap(), - None, - ), - EntryType::File { parent: _ } => { - let Key::File { id: file_hash } = key else { - panic!(""); - }; - let _ = send_to_loop - .send(KernelMessage { - id, - source: Address { - node: our_node.clone(), - process: VFS_PROCESS_ID.clone(), - }, - target: Address { - node: our_node.clone(), - process: FILESYSTEM_PROCESS_ID.clone(), - }, - rsvp: None, - message: Message::Request(Request { - inherit: true, - expects_response: Some(5), // TODO evaluate - ipc: serde_json::to_vec(&FsAction::Read(file_hash.clone())) + Some(key) => { + let entry = vfs.key_to_entry.get(key); + match entry { + None => return Err(VfsError::EntryNotFound), + Some(entry) => match &entry.entry_type { + EntryType::Dir { children, .. } => { + let paths: Vec = children + .iter() + .filter_map(|child_key| { + vfs.key_to_entry + .get(child_key) + .map(|child| child.full_path.clone()) + }) + .collect(); + ( + serde_json::to_vec(&VfsResponse::GetEntry { + is_file: false, + children: paths, + }) + .unwrap(), + None, + ) + } + EntryType::File { parent: _ } => { + let Key::File { id: file_hash } = key else { + return Err(VfsError::InternalError); + }; + let _ = send_to_loop + .send(KernelMessage { + id, + source: Address { + node: our_node.clone(), + process: VFS_PROCESS_ID.clone(), + }, + target: Address { + node: our_node.clone(), + process: FILESYSTEM_PROCESS_ID.clone(), + }, + rsvp: None, + message: Message::Request(Request { + inherit: true, + expects_response: Some(5), // TODO evaluate + ipc: serde_json::to_vec(&FsAction::Read( + file_hash.clone(), + )) .unwrap(), - metadata: None, - }), - payload: None, - signed_capabilities: None, - }) - .await; - let read_response = recv_response.recv().await.unwrap(); - let KernelMessage { - message, payload, .. - } = read_response; - let Message::Response((Response { ipc, .. }, None)) = message else { - panic!(""); - }; - let Ok(FsResponse::Read(read_hash)) = - serde_json::from_slice::>(&ipc) - .unwrap() - else { - println!("vfs: GetEntry fail fs error\r"); - panic!(""); - }; - // TODO get rid of PANICS! - assert_eq!(file_hash, read_hash); - let Some(payload) = payload else { - panic!(""); - }; - ( - serde_json::to_vec(&VfsResponse::GetEntry { - is_file: true, - children: vec![], - }) - .unwrap(), - Some(payload.bytes), - ) - } - }, - }, + metadata: None, + }), + payload: None, + signed_capabilities: None, + }) + .await; + let read_response = recv_response.recv().await.unwrap(); + let KernelMessage { + message, payload, .. + } = read_response; + let Message::Response((Response { ipc, .. }, None)) = message + else { + return Err(VfsError::InternalError); + }; + + let Ok(FsResponse::Read(_read_hash)) = + serde_json::from_slice::>(&ipc) + .unwrap() + else { + return Err(VfsError::InternalError); + }; + let Some(payload) = payload else { + return Err(VfsError::InternalError); + }; + ( + serde_json::to_vec(&VfsResponse::GetEntry { + is_file: true, + children: vec![], + }) + .unwrap(), + Some(payload.bytes), + ) + } + }, + } + } } } VfsAction::GetFileChunk { - ref full_path, + mut full_path, offset, length, } => { + full_path = clean_path(&full_path); let file_hash = { - let mut vfs = vfs.lock().await; - let Some(key) = vfs.path_to_key.remove(full_path) else { + let vfs = vfs.lock().await; + let Some(key) = vfs.path_to_key.get(&full_path) else { return Err(VfsError::EntryNotFound); }; - let key2 = key.clone(); - let Key::File { id: file_hash } = key2 else { - panic!(""); // TODO + let Key::File { id: file_hash } = key else { + return Err(VfsError::InternalError); }; - vfs.path_to_key.insert(full_path.clone(), key); - file_hash + *file_hash }; let _ = send_to_loop @@ -1504,16 +1428,19 @@ async fn match_request( message, payload, .. } = read_response; let Message::Response((Response { ipc, .. }, None)) = message else { - panic!("") + return Err(VfsError::InternalError); }; + let Ok(FsResponse::Read(read_hash)) = serde_json::from_slice::>(&ipc).unwrap() else { - panic!(""); + return Err(VfsError::InternalError); + }; + if read_hash != file_hash { + return Err(VfsError::InternalError); }; - assert_eq!(file_hash, read_hash); let Some(payload) = payload else { - panic!(""); + return Err(VfsError::InternalError); }; ( @@ -1521,7 +1448,8 @@ async fn match_request( Some(payload.bytes), ) } - VfsAction::GetEntryLength(ref full_path) => { + VfsAction::GetEntryLength(mut full_path) => { + full_path = clean_path(&full_path); if full_path.chars().last() == Some('/') { ( serde_json::to_vec(&VfsResponse::GetEntryLength(None)).unwrap(), @@ -1529,16 +1457,14 @@ async fn match_request( ) } else { let file_hash = { - let mut vfs = vfs.lock().await; - let Some(key) = vfs.path_to_key.remove(full_path) else { + let vfs = vfs.lock().await; + let Some(key) = vfs.path_to_key.get(&full_path) else { return Err(VfsError::EntryNotFound); }; - let key2 = key.clone(); - let Key::File { id: file_hash } = key2 else { - panic!(""); // TODO + let Key::File { id: file_hash } = key else { + return Err(VfsError::InternalError); }; - vfs.path_to_key.insert(full_path.clone(), key); - file_hash + *file_hash }; let _ = send_to_loop @@ -1566,12 +1492,13 @@ async fn match_request( let length_response = recv_response.recv().await.unwrap(); let KernelMessage { message, .. } = length_response; let Message::Response((Response { ipc, .. }, None)) = message else { - panic!("") + return Err(VfsError::InternalError); }; + let Ok(FsResponse::Length(length)) = serde_json::from_slice::>(&ipc).unwrap() else { - panic!(""); + return Err(VfsError::InternalError); }; ( From 199e9587d403fc9ce096b3cef3b3d7d1d03cdfef Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Fri, 3 Nov 2023 17:41:34 -0700 Subject: [PATCH 06/24] add tester tweaks to get it working --- Cargo.toml | 2 + modules/tester/Cargo-component.lock | 3 + modules/tester/Cargo.lock | 474 ++++++++++++++++++++++++++++ modules/tester/Cargo.toml | 31 ++ modules/tester/pkg/manifest.json | 12 + modules/tester/pkg/metadata.json | 5 + modules/tester/src/kernel_types.rs | 1 + modules/tester/src/lib.rs | 157 +++++++++ modules/tester/src/process_lib.rs | 1 + src/filesystem/mod.rs | 9 + src/terminal.rs | 1 - 11 files changed, 695 insertions(+), 1 deletion(-) create mode 100644 modules/tester/Cargo-component.lock create mode 100644 modules/tester/Cargo.lock create mode 100644 modules/tester/Cargo.toml create mode 100644 modules/tester/pkg/manifest.json create mode 100644 modules/tester/pkg/metadata.json create mode 120000 modules/tester/src/kernel_types.rs create mode 100644 modules/tester/src/lib.rs create mode 120000 modules/tester/src/process_lib.rs diff --git a/Cargo.toml b/Cargo.toml index 4279b304..2c73858e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,8 @@ sha2 = "0.10" walkdir = "2.4" zip = "0.6" +[features] +simulation-mode = [] [dependencies] aes-gcm = "0.10.2" diff --git a/modules/tester/Cargo-component.lock b/modules/tester/Cargo-component.lock new file mode 100644 index 00000000..00bc239d --- /dev/null +++ b/modules/tester/Cargo-component.lock @@ -0,0 +1,3 @@ +# This file is automatically generated by cargo-component. +# It is not intended for manual editing. +version = 1 diff --git a/modules/tester/Cargo.lock b/modules/tester/Cargo.lock new file mode 100644 index 00000000..c6c9d91f --- /dev/null +++ b/modules/tester/Cargo.lock @@ -0,0 +1,474 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + +[[package]] +name = "cargo-component-bindings" +version = "0.1.0" +source = "git+https://github.com/bytecodealliance/cargo-component#6a2996f280dd8671a2a2d3c83cbe09a39225b526" +dependencies = [ + "cargo-component-macro", + "wit-bindgen", +] + +[[package]] +name = "cargo-component-macro" +version = "0.1.0" +source = "git+https://github.com/bytecodealliance/cargo-component#6a2996f280dd8671a2a2d3c83cbe09a39225b526" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", + "wit-bindgen-rust-lib", + "wit-component", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "form_urlencoded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "id-arena" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown", + "serde", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "memchr" +version = "2.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pulldown-cmark" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998" +dependencies = [ + "bitflags 1.3.2", + "memchr", + "unicase", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "semver" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" + +[[package]] +name = "serde" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "smallvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" + +[[package]] +name = "spdx" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b19b32ed6d899ab23174302ff105c1577e45a06b08d4fe0a9dd13ce804bbbf71" +dependencies = [ + "smallvec", +] + +[[package]] +name = "syn" +version = "2.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tester" +version = "0.1.0" +dependencies = [ + "anyhow", + "bincode", + "cargo-component-bindings", + "serde", + "serde_json", + "thiserror", + "wit-bindgen", +] + +[[package]] +name = "thiserror" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "url" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasm-encoder" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba64e81215916eaeb48fee292f29401d69235d62d8b8fd92a7b2844ec5ae5f7" +dependencies = [ + "leb128", +] + +[[package]] +name = "wasm-metadata" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08dc59d1fa569150851542143ca79438ca56845ccb31696c70225c638e063471" +dependencies = [ + "anyhow", + "indexmap", + "serde", + "serde_json", + "spdx", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.112.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e986b010f47fcce49cf8ea5d5f9e5d2737832f12b53ae8ae785bbe895d0877bf" +dependencies = [ + "indexmap", + "semver", +] + +[[package]] +name = "wit-bindgen" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8a3e8e965dc50e6eb4410d9a11720719fadc6a1713803ea5f3be390b81c8279" +dependencies = [ + "bitflags 2.4.0", + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77255512565dfbd0b61de466e854918041d1da53c7bc049d6188c6e02643dc1e" +dependencies = [ + "anyhow", + "wit-component", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "399c60e6ea8598d1380e792f13d557007834f0fb799fea6503408cbc5debb4ae" +dependencies = [ + "anyhow", + "heck", + "wasm-metadata", + "wit-bindgen-core", + "wit-bindgen-rust-lib", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-lib" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd9fb7a43c7dc28b0b727d6ae01bf369981229b7539e768fba2b7a4df13feeeb" +dependencies = [ + "heck", + "wit-bindgen-core", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44cea5ed784da06da0e55836a6c160e7502dbe28771c2368a595e8606243bf22" +dependencies = [ + "anyhow", + "proc-macro2", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", + "wit-bindgen-rust-lib", + "wit-component", +] + +[[package]] +name = "wit-component" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d9f2d16dd55d1a372dcfd4b7a466ea876682a5a3cb97e71ec9eef04affa876" +dependencies = [ + "anyhow", + "bitflags 2.4.0", + "indexmap", + "log", + "serde", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61e8b849bea13cc2315426b16efe6eb6813466d78f5fde69b0bb150c9c40e0dc" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "pulldown-cmark", + "semver", + "unicode-xid", + "url", +] diff --git a/modules/tester/Cargo.toml b/modules/tester/Cargo.toml new file mode 100644 index 00000000..82b8257a --- /dev/null +++ b/modules/tester/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "tester" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[profile.release] +panic = "abort" +opt-level = "s" +lto = true + +[dependencies] +anyhow = "1.0" +bincode = "1.3.3" +cargo-component-bindings = { git = "https://github.com/bytecodealliance/cargo-component" } +serde = {version = "1.0", features = ["derive"] } +serde_json = "1.0" +thiserror = "1.0" +wit-bindgen = { version = "0.11.0", default_features = false } + +[lib] +crate-type = ["cdylib"] + +[package.metadata.component] +package = "component:uq-process" + +[package.metadata.component.target] +path = "wit" + +[package.metadata.component.dependencies] diff --git a/modules/tester/pkg/manifest.json b/modules/tester/pkg/manifest.json new file mode 100644 index 00000000..6fde6d7a --- /dev/null +++ b/modules/tester/pkg/manifest.json @@ -0,0 +1,12 @@ +[ + { + "process_name": "tester", + "process_wasm_path": "/tester.wasm", + "on_panic": "Restart", + "request_networking": true, + "request_messaging": [ + "net:sys:uqbar" + ], + "public": true + } +] diff --git a/modules/tester/pkg/metadata.json b/modules/tester/pkg/metadata.json new file mode 100644 index 00000000..1b5b73d5 --- /dev/null +++ b/modules/tester/pkg/metadata.json @@ -0,0 +1,5 @@ +{ + "package": "tester", + "publisher": "uqbar", + "version": [0, 1, 0] +} diff --git a/modules/tester/src/kernel_types.rs b/modules/tester/src/kernel_types.rs new file mode 120000 index 00000000..8311791c --- /dev/null +++ b/modules/tester/src/kernel_types.rs @@ -0,0 +1 @@ +../../../src/kernel_types.rs \ No newline at end of file diff --git a/modules/tester/src/lib.rs b/modules/tester/src/lib.rs new file mode 100644 index 00000000..22bb58d2 --- /dev/null +++ b/modules/tester/src/lib.rs @@ -0,0 +1,157 @@ +cargo_component_bindings::generate!(); + +use serde::{Serialize, Deserialize}; +use std::collections::{HashMap, HashSet}; + +use bindings::component::uq_process::types::*; +use bindings::{create_capability, get_capability, Guest, has_capability, print_to_terminal, receive, send_request, send_response, share_capability, spawn}; + +mod kernel_types; +use kernel_types as kt; +mod process_lib; + +struct Component; + +#[derive(Debug, Serialize, Deserialize)] +enum TesterRequest { + Run, +} + +#[derive(Debug, Serialize, Deserialize, thiserror::Error)] +enum TesterError { + #[error("RejectForeign")] + RejectForeign, + #[error("UnexpectedResponse")] + UnexpectedResponse, +} + +fn make_vfs_address(our: &Address) -> anyhow::Result
{ + Ok(Address { + node: our.node.clone(), + process: ProcessId::from_str("vfs:sys:uqbar")?, + }) +} + +fn handle_message (our: &Address) -> anyhow::Result<()> { + let (source, message) = receive().unwrap(); + // let (source, message) = receive()?; + + if our.node != source.node { + return Err(TesterError::RejectForeign.into()); + } + + match message { + Message::Response(_) => { + return Err(TesterError::UnexpectedResponse.into()); + }, + Message::Request(Request { ipc, .. }) => { + match process_lib::parse_message_ipc(&ipc)? { + TesterRequest::Run => { + print_to_terminal(0, "tester: got Run"); + let (_, response) = process_lib::send_and_await_response( + &make_vfs_address(&our)?, + false, + serde_json::to_vec(&kt::VfsRequest { + drive: "tester:uqbar".into(), + action: kt::VfsAction::GetEntry("/".into()), + })?, + None, + None, + 5, + )?; + let Message::Response((response, _)) = response else { panic!("") }; + let kt::VfsResponse::GetEntry { children, .. } = + process_lib::parse_message_ipc(&response.ipc)? else { panic!("") }; + let mut children: HashSet<_> = children.into_iter().collect(); + children.remove("/manifest.json"); + children.remove("/metadata.json"); + children.remove("/tester.wasm"); + + print_to_terminal(0, &format!("tester: running {:?}...", children)); + + for child in &children { + let (_, response) = process_lib::send_and_await_response( + &make_vfs_address(&our)?, + false, + serde_json::to_vec(&kt::VfsRequest { + drive: "tester:uqbar".into(), + action: kt::VfsAction::GetEntryLength(child.into()), + })?, + None, + None, + 5, + )?; + let Message::Response((response, _)) = response else { panic!("") }; + let kt::VfsResponse::GetEntryLength(length) = + process_lib::parse_message_ipc(&response.ipc)? else { panic!("") }; + + print_to_terminal(0, &format!("tester: child {} length {:?}", child, length)); + + match spawn( + None, + child, + &OnPanic::None, // TODO: notify us + &Capabilities::All, + false, // not public + ) { + Ok(child_process_id) => child_process_id, + Err(e) => { + print_to_terminal(0, &format!("couldn't spawn {}: {}", child, e)); + panic!("couldn't spawn"); // TODO + } + }; + } + send_response( + &Response { + inherit: false, + ipc, + metadata: None, + }, + None, + ); + }, + } + Ok(()) + }, + } +} + +impl Guest for Component { + fn init(our: Address) { + print_to_terminal(0, "tester: begin"); + + // orchestrate tests using external scripts + // -> must give drive cap to rpc + // TODO: need read as well? + let drive_cap = get_capability( + &make_vfs_address(&our).unwrap(), + &serde_json::to_string(&serde_json::json!({ + "kind": "write", + "drive": "tester:uqbar", + })).unwrap() + ).unwrap(); + share_capability(&ProcessId::from_str("http_server:sys:uqbar").unwrap(), &drive_cap); + + loop { + match handle_message(&our) { + Ok(()) => {}, + Err(e) => { + print_to_terminal(0, format!( + "tester: error: {:?}", + e, + ).as_str()); + // if let Some(e) = e.downcast_ref::() { + // send_response( + // &Response { + // inherit: false, + // ipc: serde_json::to_vec(&e).unwrap(), + // metadata: None, + // }, + // None, + // ); + // } + }, + }; + } + } +} diff --git a/modules/tester/src/process_lib.rs b/modules/tester/src/process_lib.rs new file mode 120000 index 00000000..77367fe0 --- /dev/null +++ b/modules/tester/src/process_lib.rs @@ -0,0 +1 @@ +../../../src/process_lib.rs \ No newline at end of file diff --git a/src/filesystem/mod.rs b/src/filesystem/mod.rs index f24ccc86..dfe13fb6 100644 --- a/src/filesystem/mod.rs +++ b/src/filesystem/mod.rs @@ -149,6 +149,14 @@ async fn bootstrap( let mut vfs_messages = Vec::new(); for (package_name, mut package) in packages { + // special case tester: only load it in if in simulation mode + if package_name == "tester" { + #[cfg(not(feature = "simulation-mode"))] + continue; + #[cfg(feature = "simulation-mode")] + {} + } + println!("fs: handling package {package_name}...\r"); // get and read metadata.json let Ok(mut package_metadata_zip) = package.by_name("metadata.json") else { @@ -361,6 +369,7 @@ async fn bootstrap( .write(&kernel_process_id, &serialized_process_map) .await; } + Ok(vfs_messages) } diff --git a/src/terminal.rs b/src/terminal.rs index 8de36092..90b0cf6a 100644 --- a/src/terminal.rs +++ b/src/terminal.rs @@ -186,7 +186,6 @@ pub async fn terminal( let event = reader.next().fuse(); tokio::select! { - // aaa prints = print_rx.recv() => match prints { Some(printout) => { let now = Local::now(); From 1b5a056707369d1ac28f9ee3955eefbe868798ce Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Mon, 6 Nov 2023 20:44:16 -0800 Subject: [PATCH 07/24] add port bind print --- src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main.rs b/src/main.rs index 0b90b817..5ff07c25 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ use anyhow::Result; use clap::Parser; use dotenv; +use ring::signature::KeyPair; use std::env; use std::sync::Arc; use tokio::sync::{mpsc, oneshot}; @@ -166,6 +167,7 @@ async fn main() { }; let http_server_port = http_server::find_open_port(args.port).await.unwrap(); + println!("runtime bound port {}\r", http_server_port); let (our, decoded_keyfile) = match args.password { Some(password) => { match fs::read(format!("{}/.keys", home_directory_path)).await { From b5a5e31517ef229c3a41079afbf37a2773f9f5de Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Mon, 6 Nov 2023 21:57:26 -0800 Subject: [PATCH 08/24] fix tester --- modules/tester/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/tester/src/lib.rs b/modules/tester/src/lib.rs index 727ca092..ef0d887e 100644 --- a/modules/tester/src/lib.rs +++ b/modules/tester/src/lib.rs @@ -59,7 +59,7 @@ fn handle_message (our: &Address) -> anyhow::Result<()> { let wit::Message::Response((response, _)) = response else { panic!("") }; let kt::VfsResponse::GetEntry { children, .. } = - serde_json::from_slice(&ipc)? else { panic!("") }; + serde_json::from_slice(&response.ipc)? else { panic!("") }; let mut children: HashSet<_> = children.into_iter().collect(); children.remove("/manifest.json"); children.remove("/metadata.json"); @@ -78,7 +78,7 @@ fn handle_message (our: &Address) -> anyhow::Result<()> { let wit::Message::Response((response, _)) = response else { panic!("") }; let kt::VfsResponse::GetEntryLength(length) = - serde_json::from_slice(&ipc)? else { panic!("") }; + serde_json::from_slice(&response.ipc)? else { panic!("") }; wit::print_to_terminal(0, &format!("tester: child {} length {:?}", child, length)); From 1900bdbfb8269a60418a87d20c9c31188de97171 Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Tue, 7 Nov 2023 14:43:52 -0800 Subject: [PATCH 09/24] add tester, sqlite, key_value fixes --- modules/key_value/key_value/src/lib.rs | 22 ++++++----- modules/sqlite/sqlite/src/lib.rs | 6 ++- modules/tester/src/lib.rs | 53 +++++++++++++------------- 3 files changed, 44 insertions(+), 37 deletions(-) diff --git a/modules/key_value/key_value/src/lib.rs b/modules/key_value/key_value/src/lib.rs index a9486cf0..4dfd2705 100644 --- a/modules/key_value/key_value/src/lib.rs +++ b/modules/key_value/key_value/src/lib.rs @@ -104,19 +104,23 @@ fn handle_message(our: &Address, db_to_process: &mut DbToProcess) -> anyhow::Res .send_and_await_response(15)??; // (2) - let vfs_read = wit::get_capability(&vfs_address, &make_vfs_cap("read", &vfs_drive)) - .ok_or(anyhow::anyhow!( - "New failed: no vfs 'read' capability found" - ))?; - let vfs_write = - wit::get_capability(&vfs_address, &make_vfs_cap("write", &vfs_drive)).ok_or( - anyhow::anyhow!("New failed: no vfs 'write' capability found"), - )?; + let vfs_read = wit::get_capability( + &vfs_address, + &make_vfs_cap("read", &vfs_drive) + ).ok_or(anyhow::anyhow!("New failed: no vfs 'read' capability found"))?; + let vfs_write = wit::get_capability( + &vfs_address, + &make_vfs_cap("write", &vfs_drive) + ).ok_or(anyhow::anyhow!("New failed: no vfs 'write' capability found"))?; + let messaging = wit::get_capability( + &source, + &"\"messaging\"".into(), + ).ok_or(anyhow::anyhow!("New failed: no source 'messaging' capability found"))?; let spawned_process_id = match wit::spawn( None, "/key_value_worker.wasm", &wit::OnPanic::None, // TODO: notify us - &wit::Capabilities::Some(vec![vfs_read, vfs_write]), + &wit::Capabilities::Some(vec![vfs_read, vfs_write, messaging]), false, // not public ) { Ok(spawned_process_id) => spawned_process_id, diff --git a/modules/sqlite/sqlite/src/lib.rs b/modules/sqlite/sqlite/src/lib.rs index d2a19b37..8b3bc20e 100644 --- a/modules/sqlite/sqlite/src/lib.rs +++ b/modules/sqlite/sqlite/src/lib.rs @@ -114,11 +114,15 @@ fn handle_message ( &vfs_address, &make_vfs_cap("write", &vfs_drive), ).ok_or(anyhow::anyhow!("New failed: no vfs 'write' capability found"))?; + let messaging = wit::get_capability( + &source, + &"\"messaging\"".into(), + ).ok_or(anyhow::anyhow!("New failed: no source 'messaging' capability found"))?; let spawned_process_id = match wit::spawn( None, "/sqlite_worker.wasm", &wit::OnPanic::None, // TODO: notify us - &wit::Capabilities::Some(vec![vfs_read, vfs_write]), + &wit::Capabilities::Some(vec![vfs_read, vfs_write, messaging]), false, // not public ) { Ok(spawned_process_id) => spawned_process_id, diff --git a/modules/tester/src/lib.rs b/modules/tester/src/lib.rs index ef0d887e..e1a97ba2 100644 --- a/modules/tester/src/lib.rs +++ b/modules/tester/src/lib.rs @@ -18,6 +18,12 @@ enum TesterRequest { Run, } +#[derive(Debug, Serialize, Deserialize)] +enum TesterResponse { + Pass, + Fail, +} + #[derive(Debug, Serialize, Deserialize, thiserror::Error)] enum TesterError { #[error("RejectForeign")] @@ -68,21 +74,7 @@ fn handle_message (our: &Address) -> anyhow::Result<()> { wit::print_to_terminal(0, &format!("tester: running {:?}...", children)); for child in &children { - let (_, response) = Request::new() - .target(make_vfs_address(&our)?)? - .ipc_bytes(serde_json::to_vec(&kt::VfsRequest { - drive: "tester:uqbar".into(), - action: kt::VfsAction::GetEntryLength(child.into()), - })?) - .send_and_await_response(5)??; - - let wit::Message::Response((response, _)) = response else { panic!("") }; - let kt::VfsResponse::GetEntryLength(length) = - serde_json::from_slice(&response.ipc)? else { panic!("") }; - - wit::print_to_terminal(0, &format!("tester: child {} length {:?}", child, length)); - - match wit::spawn( + let child_process_id = match wit::spawn( None, child, &wit::OnPanic::None, // TODO: notify us @@ -95,9 +87,23 @@ fn handle_message (our: &Address) -> anyhow::Result<()> { panic!("couldn't spawn"); // TODO } }; + + let (_, response) = Request::new() + .target(Address { + node: our.node.clone(), + process: child_process_id, + })? + .ipc_bytes(ipc.clone()) + .send_and_await_response(5)??; + + let wit::Message::Response((response, _)) = response else { panic!("") }; + let TesterResponse::Pass = serde_json::from_slice(&response.ipc)? else { + return Err(anyhow::anyhow!("{} FAIL", child)) + }; } + Response::new() - .ipc_bytes(serde_json::to_vec(&ipc).unwrap()) + .ipc_bytes(serde_json::to_vec(&TesterResponse::Pass).unwrap()) .send() .unwrap(); }, @@ -116,7 +122,6 @@ impl Guest for Component { // orchestrate tests using external scripts // -> must give drive cap to rpc - // TODO: need read as well? let drive_cap = wit::get_capability( &make_vfs_address(&our).unwrap(), &serde_json::to_string(&serde_json::json!({ @@ -134,16 +139,10 @@ impl Guest for Component { "tester: error: {:?}", e, ).as_str()); - // if let Some(e) = e.downcast_ref::() { - // send_response( - // &Response { - // inherit: false, - // ipc: serde_json::to_vec(&e).unwrap(), - // metadata: None, - // }, - // None, - // ); - // } + Response::new() + .ipc_bytes(serde_json::to_vec(&TesterResponse::Fail).unwrap()) + .send() + .unwrap(); }, }; } From 6202cd2b6a0b187987c98eeda9b13e36079d2047 Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Wed, 8 Nov 2023 13:54:30 -0800 Subject: [PATCH 10/24] tester: use process_lib git repo --- modules/tester/Cargo.lock | 1 + modules/tester/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/tester/Cargo.lock b/modules/tester/Cargo.lock index 32b56091..b0267f17 100644 --- a/modules/tester/Cargo.lock +++ b/modules/tester/Cargo.lock @@ -279,6 +279,7 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "uqbar_process_lib" version = "0.2.0" +source = "git+https://github.com/uqbar-dao/process_lib?rev=e53c124#e53c124ec95ef99c06d201d4d08dada8ec691d29" dependencies = [ "anyhow", "bincode", diff --git a/modules/tester/Cargo.toml b/modules/tester/Cargo.toml index 61361431..27dfb79c 100644 --- a/modules/tester/Cargo.toml +++ b/modules/tester/Cargo.toml @@ -16,7 +16,7 @@ bincode = "1.3.3" serde = {version = "1.0", features = ["derive"] } serde_json = "1.0" thiserror = "1.0" -uqbar_process_lib = { path = "../../process_lib" } +uqbar_process_lib = { git = "https://github.com/uqbar-dao/process_lib", rev = "e53c124" } wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "5390bab780733f1660d14c254ec985df2816bf1d" } [lib] From e0df3994a1b03e8b6fef097123e5dce0846cdcdd Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Thu, 9 Nov 2023 15:04:07 -0800 Subject: [PATCH 11/24] tester: get & store all Messages --- .../{ => test_runner}/Cargo-component.lock | 0 modules/tester/{ => test_runner}/Cargo.lock | 2 +- modules/tester/{ => test_runner}/Cargo.toml | 4 +- modules/tester/{ => test_runner}/src/lib.rs | 30 +- modules/tester/tester/Cargo-component.lock | 3 + modules/tester/tester/Cargo.lock | 411 ++++++++++++++++++ modules/tester/tester/Cargo.toml | 33 ++ modules/tester/tester/src/lib.rs | 170 ++++++++ src/kernel/mod.rs | 36 ++ 9 files changed, 681 insertions(+), 8 deletions(-) rename modules/tester/{ => test_runner}/Cargo-component.lock (100%) rename modules/tester/{ => test_runner}/Cargo.lock (99%) rename modules/tester/{ => test_runner}/Cargo.toml (93%) rename modules/tester/{ => test_runner}/src/lib.rs (82%) create mode 100644 modules/tester/tester/Cargo-component.lock create mode 100644 modules/tester/tester/Cargo.lock create mode 100644 modules/tester/tester/Cargo.toml create mode 100644 modules/tester/tester/src/lib.rs diff --git a/modules/tester/Cargo-component.lock b/modules/tester/test_runner/Cargo-component.lock similarity index 100% rename from modules/tester/Cargo-component.lock rename to modules/tester/test_runner/Cargo-component.lock diff --git a/modules/tester/Cargo.lock b/modules/tester/test_runner/Cargo.lock similarity index 99% rename from modules/tester/Cargo.lock rename to modules/tester/test_runner/Cargo.lock index b0267f17..18eaa038 100644 --- a/modules/tester/Cargo.lock +++ b/modules/tester/test_runner/Cargo.lock @@ -226,7 +226,7 @@ dependencies = [ ] [[package]] -name = "tester" +name = "test_runner" version = "0.1.0" dependencies = [ "anyhow", diff --git a/modules/tester/Cargo.toml b/modules/tester/test_runner/Cargo.toml similarity index 93% rename from modules/tester/Cargo.toml rename to modules/tester/test_runner/Cargo.toml index 27dfb79c..51eed120 100644 --- a/modules/tester/Cargo.toml +++ b/modules/tester/test_runner/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "tester" +name = "test_runner" version = "0.1.0" edition = "2021" @@ -23,7 +23,7 @@ wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = " crate-type = ["cdylib"] [package.metadata.component] -package = "component:uq-process" +package = "uqbar:process" [package.metadata.component.target] path = "wit" diff --git a/modules/tester/src/lib.rs b/modules/tester/test_runner/src/lib.rs similarity index 82% rename from modules/tester/src/lib.rs rename to modules/tester/test_runner/src/lib.rs index e1a97ba2..02af8567 100644 --- a/modules/tester/src/lib.rs +++ b/modules/tester/test_runner/src/lib.rs @@ -6,22 +6,38 @@ use uqbar_process_lib::kernel_types as kt; use uqbar_process_lib::uqbar::process::standard as wit; wit_bindgen::generate!({ - path: "../../wit", + path: "../../../wit", world: "process", exports: { world: Component, }, }); +pub type Rsvp = Option; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct KernelMessage { + pub id: u64, + pub source: kt::Address, + pub target: kt::Address, + pub rsvp: Rsvp, + pub message: kt::Message, + pub payload: Option, + pub signed_capabilities: Option>, +} + #[derive(Debug, Serialize, Deserialize)] enum TesterRequest { Run, + KernelMessage(KernelMessage), + GetFullMessage(kt::Message), } #[derive(Debug, Serialize, Deserialize)] enum TesterResponse { Pass, Fail, + GetFullMessage(Option), } #[derive(Debug, Serialize, Deserialize, thiserror::Error)] @@ -53,7 +69,7 @@ fn handle_message (our: &Address) -> anyhow::Result<()> { wit::Message::Request(wit::Request { ipc, .. }) => { match serde_json::from_slice(&ipc)? { TesterRequest::Run => { - wit::print_to_terminal(0, "tester: got Run"); + wit::print_to_terminal(0, "test_runner: got Run"); let (_, response) = Request::new() .target(make_vfs_address(&our)?)? @@ -70,8 +86,9 @@ fn handle_message (our: &Address) -> anyhow::Result<()> { children.remove("/manifest.json"); children.remove("/metadata.json"); children.remove("/tester.wasm"); + children.remove("/test_runner.wasm"); - wit::print_to_terminal(0, &format!("tester: running {:?}...", children)); + wit::print_to_terminal(0, &format!("test_runner: running {:?}...", children)); for child in &children { let child_process_id = match wit::spawn( @@ -102,11 +119,14 @@ fn handle_message (our: &Address) -> anyhow::Result<()> { }; } + wit::print_to_terminal(0, &format!("test_runner: done running {:?}", children)); + Response::new() .ipc_bytes(serde_json::to_vec(&TesterResponse::Pass).unwrap()) .send() .unwrap(); }, + TesterRequest::KernelMessage(_) | TesterRequest::GetFullMessage(_) => { unimplemented!() }, } Ok(()) }, @@ -116,7 +136,7 @@ fn handle_message (our: &Address) -> anyhow::Result<()> { struct Component; impl Guest for Component { fn init(our: String) { - wit::print_to_terminal(0, "tester: begin"); + wit::print_to_terminal(0, "test_runner: begin"); let our = Address::from_str(&our).unwrap(); @@ -136,7 +156,7 @@ impl Guest for Component { Ok(()) => {}, Err(e) => { wit::print_to_terminal(0, format!( - "tester: error: {:?}", + "test_runner: error: {:?}", e, ).as_str()); Response::new() diff --git a/modules/tester/tester/Cargo-component.lock b/modules/tester/tester/Cargo-component.lock new file mode 100644 index 00000000..00bc239d --- /dev/null +++ b/modules/tester/tester/Cargo-component.lock @@ -0,0 +1,3 @@ +# This file is automatically generated by cargo-component. +# It is not intended for manual editing. +version = 1 diff --git a/modules/tester/tester/Cargo.lock b/modules/tester/tester/Cargo.lock new file mode 100644 index 00000000..23099615 --- /dev/null +++ b/modules/tester/tester/Cargo.lock @@ -0,0 +1,411 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "id-arena" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown", + "serde", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + +[[package]] +name = "libc" +version = "0.2.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "semver" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" + +[[package]] +name = "serde" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "smallvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" + +[[package]] +name = "spdx" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b19b32ed6d899ab23174302ff105c1577e45a06b08d4fe0a9dd13ce804bbbf71" +dependencies = [ + "smallvec", +] + +[[package]] +name = "syn" +version = "2.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tester" +version = "0.1.0" +dependencies = [ + "anyhow", + "bincode", + "indexmap", + "serde", + "serde_json", + "thiserror", + "uqbar_process_lib", + "wit-bindgen", +] + +[[package]] +name = "thiserror" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "uqbar_process_lib" +version = "0.2.0" +dependencies = [ + "anyhow", + "bincode", + "rand", + "serde", + "wit-bindgen", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-encoder" +version = "0.36.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "822b645bf4f2446b949776ffca47e2af60b167209ffb70814ef8779d299cd421" +dependencies = [ + "leb128", +] + +[[package]] +name = "wasm-metadata" +version = "0.10.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2167ce53b2faa16a92c6cafd4942cff16c9a4fa0c5a5a0a41131ee4e49fc055f" +dependencies = [ + "anyhow", + "indexmap", + "serde", + "serde_derive", + "serde_json", + "spdx", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a58e28b80dd8340cb07b8242ae654756161f6fc8d0038123d679b7b99964fa50" +dependencies = [ + "indexmap", + "semver", +] + +[[package]] +name = "wit-bindgen" +version = "0.13.1" +source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d" +dependencies = [ + "bitflags", + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.13.1" +source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d" +dependencies = [ + "anyhow", + "wit-component", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.13.2" +source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d" +dependencies = [ + "anyhow", + "heck", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.13.1" +source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d" +dependencies = [ + "anyhow", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", + "wit-component", +] + +[[package]] +name = "wit-component" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "480cc1a078b305c1b8510f7c455c76cbd008ee49935f3a6c5fd5e937d8d95b1e" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43771ee863a16ec4ecf9da0fc65c3bbd4a1235c8e3da5f094b562894843dfa76" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", +] diff --git a/modules/tester/tester/Cargo.toml b/modules/tester/tester/Cargo.toml new file mode 100644 index 00000000..0f325448 --- /dev/null +++ b/modules/tester/tester/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "tester" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[profile.release] +panic = "abort" +opt-level = "s" +lto = true + +[dependencies] +anyhow = "1.0" +bincode = "1.3.3" +indexmap = "2.1" +serde = {version = "1.0", features = ["derive"] } +serde_json = "1.0" +thiserror = "1.0" +uqbar_process_lib = { path = "../../../../process_lib" } +# uqbar_process_lib = { git = "https://github.com/uqbar-dao/process_lib", rev = "9684d33" } +wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "5390bab780733f1660d14c254ec985df2816bf1d" } + +[lib] +crate-type = ["cdylib"] + +[package.metadata.component] +package = "uqbar:process" + +[package.metadata.component.target] +path = "wit" + +[package.metadata.component.dependencies] diff --git a/modules/tester/tester/src/lib.rs b/modules/tester/tester/src/lib.rs new file mode 100644 index 00000000..ada4f026 --- /dev/null +++ b/modules/tester/tester/src/lib.rs @@ -0,0 +1,170 @@ +use serde::{Serialize, Deserialize}; +use std::collections::{HashMap, HashSet}; + +use indexmap::map::IndexMap; + +use uqbar_process_lib::{Address, ProcessId, Request, Response}; +use uqbar_process_lib::kernel_types as kt; +use uqbar_process_lib::uqbar::process::standard as wit; + +wit_bindgen::generate!({ + path: "../../../wit", + world: "process", + exports: { + world: Component, + }, +}); + +type Rsvp = Option; + +#[derive(Clone, Debug, Serialize, Deserialize)] +struct KernelMessage { + pub id: u64, + pub source: kt::Address, + pub target: kt::Address, + pub rsvp: Rsvp, + pub message: kt::Message, + pub payload: Option, + pub signed_capabilities: Option>, +} + +#[derive(Debug, Serialize, Deserialize)] +enum TesterRequest { + Run, + KernelMessage(KernelMessage), + GetFullMessage(kt::Message), +} + +#[derive(Debug, Serialize, Deserialize)] +enum TesterResponse { + Pass, + Fail, + GetFullMessage(Option), +} + +#[derive(Debug, Serialize, Deserialize, thiserror::Error)] +enum TesterError { + #[error("RejectForeign")] + RejectForeign, + #[error("UnexpectedResponse")] + UnexpectedResponse, +} + +type Messages = IndexMap; + +fn make_vfs_address(our: &wit::Address) -> anyhow::Result
{ + Ok(wit::Address { + node: our.node.clone(), + process: ProcessId::from_str("vfs:sys:uqbar")?, + }) +} + +fn handle_message(our: &Address, messages: &mut Messages) -> anyhow::Result<()> { + let (source, message) = wit::receive().unwrap(); + + if our.node != source.node { + return Err(TesterError::RejectForeign.into()); + } + + match message { + wit::Message::Response((wit::Response { ipc, .. }, _)) => { + match serde_json::from_slice(&ipc)? { + TesterResponse::Pass | TesterResponse::Fail => { + if (source.process.package_name != "tester") + | (source.process.publisher_node != "uqbar") { + return Err(TesterError::UnexpectedResponse.into()); + } + Response::new() + .ipc_bytes(ipc) + .send() + .unwrap(); + }, + TesterResponse::GetFullMessage(_) => { unimplemented!() } + } + Ok(()) + }, + wit::Message::Request(wit::Request { ipc, .. }) => { + match serde_json::from_slice(&ipc)? { + TesterRequest::Run => { + wit::print_to_terminal(0, "tester: got Run"); + + let child = "/test_runner.wasm"; + let child_process_id = match wit::spawn( + None, + child, + &wit::OnPanic::None, // TODO: notify us + &wit::Capabilities::All, + false, // not public + ) { + Ok(child_process_id) => child_process_id, + Err(e) => { + wit::print_to_terminal(0, &format!("couldn't spawn {}: {}", child, e)); + panic!("couldn't spawn"); // TODO + } + }; + + Request::new() + .target(Address { + node: our.node.clone(), + process: child_process_id, + })? + .ipc_bytes(ipc.clone()) + .expects_response(15) + .send()?; + }, + TesterRequest::KernelMessage(kernel_message) => { + messages.insert(kernel_message.message.clone(), kernel_message); + }, + TesterRequest::GetFullMessage(message) => { + Response::new() + .ipc_bytes(serde_json::to_vec(&TesterResponse::GetFullMessage( + match messages.get(&message) { + None => None, + Some(m) => Some(m.clone()), + } + )).unwrap()) + .send() + .unwrap(); + }, + } + Ok(()) + }, + } +} + +struct Component; +impl Guest for Component { + fn init(our: String) { + wit::print_to_terminal(0, "tester: begin"); + + let our = Address::from_str(&our).unwrap(); + let mut messages: Messages = IndexMap::new(); + + // orchestrate tests using external scripts + // -> must give drive cap to rpc + let drive_cap = wit::get_capability( + &make_vfs_address(&our).unwrap(), + &serde_json::to_string(&serde_json::json!({ + "kind": "write", + "drive": "tester:uqbar", + })).unwrap() + ).unwrap(); + wit::share_capability(&ProcessId::from_str("http_server:sys:uqbar").unwrap(), &drive_cap); + + loop { + match handle_message(&our, &mut messages) { + Ok(()) => {}, + Err(e) => { + wit::print_to_terminal(0, format!( + "tester: error: {:?}", + e, + ).as_str()); + Response::new() + .ipc_bytes(serde_json::to_vec(&TesterResponse::Fail).unwrap()) + .send() + .unwrap(); + }, + }; + } + } +} diff --git a/src/kernel/mod.rs b/src/kernel/mod.rs index 68fc3ce1..c2a4e9ab 100644 --- a/src/kernel/mod.rs +++ b/src/kernel/mod.rs @@ -1914,6 +1914,9 @@ async fn make_event_loop( .await .unwrap(); + #[cfg(feature = "simulation-mode")] + let tester_process_id = t::ProcessId::new(Some("tester"), "tester", "uqbar"); + // main message loop loop { tokio::select! { @@ -2066,6 +2069,39 @@ async fn make_event_loop( content: format!("event loop: got message: {}", kernel_message) } ).await; + + // send every single event to tester + #[cfg(feature = "simulation-mode")] + match senders.get(&tester_process_id) { + None => {} + Some(ProcessSender::Runtime(_)) => {} + Some(ProcessSender::Userspace(sender)) => { + let wrapped_kernel_message = t::KernelMessage { + id: 0, + source: t::Address { + node: our_name.clone(), + process: KERNEL_PROCESS_ID.clone(), + }, + target: t::Address { + node: our_name.clone(), + process: tester_process_id.clone(), + }, + rsvp: None, + message: t::Message::Request(t::Request { + inherit: false, + expects_response: None, + ipc: serde_json::to_vec(&serde_json::json!({ + "KernelMessage": kernel_message, + })).unwrap(), + metadata: None, + }), + payload: None, + signed_capabilities: None, + }; + sender.send(Ok(wrapped_kernel_message)).await.unwrap(); + } + } + if our_name != kernel_message.target.node { // unrecoverable if fails send_to_net.send(kernel_message).await.expect("fatal: net module died"); From 0239d6c02a9e0d6e51bfff791b5de47f132c375a Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Mon, 27 Nov 2023 19:13:58 -0800 Subject: [PATCH 12/24] improve output --- modules/tester/test_runner/src/lib.rs | 80 +++++-------------- .../tester/test_runner/src/tester_types.rs | 1 + modules/tester/tester/src/lib.rs | 63 ++++----------- modules/tester/tester/src/tester_types.rs | 1 + modules/tester/tester_types.rs | 77 ++++++++++++++++++ 5 files changed, 112 insertions(+), 110 deletions(-) create mode 120000 modules/tester/test_runner/src/tester_types.rs create mode 120000 modules/tester/tester/src/tester_types.rs create mode 100644 modules/tester/tester_types.rs diff --git a/modules/tester/test_runner/src/lib.rs b/modules/tester/test_runner/src/lib.rs index 02af8567..12a65832 100644 --- a/modules/tester/test_runner/src/lib.rs +++ b/modules/tester/test_runner/src/lib.rs @@ -5,6 +5,9 @@ use uqbar_process_lib::{Address, ProcessId, Request, Response}; use uqbar_process_lib::kernel_types as kt; use uqbar_process_lib::uqbar::process::standard as wit; +mod tester_types; +use tester_types as tt; + wit_bindgen::generate!({ path: "../../../wit", world: "process", @@ -13,41 +16,6 @@ wit_bindgen::generate!({ }, }); -pub type Rsvp = Option; - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct KernelMessage { - pub id: u64, - pub source: kt::Address, - pub target: kt::Address, - pub rsvp: Rsvp, - pub message: kt::Message, - pub payload: Option, - pub signed_capabilities: Option>, -} - -#[derive(Debug, Serialize, Deserialize)] -enum TesterRequest { - Run, - KernelMessage(KernelMessage), - GetFullMessage(kt::Message), -} - -#[derive(Debug, Serialize, Deserialize)] -enum TesterResponse { - Pass, - Fail, - GetFullMessage(Option), -} - -#[derive(Debug, Serialize, Deserialize, thiserror::Error)] -enum TesterError { - #[error("RejectForeign")] - RejectForeign, - #[error("UnexpectedResponse")] - UnexpectedResponse, -} - fn make_vfs_address(our: &wit::Address) -> anyhow::Result
{ Ok(wit::Address { node: our.node.clone(), @@ -55,20 +23,20 @@ fn make_vfs_address(our: &wit::Address) -> anyhow::Result
{ }) } -fn handle_message (our: &Address) -> anyhow::Result<()> { +fn handle_message(our: &Address) -> anyhow::Result<()> { let (source, message) = wit::receive().unwrap(); if our.node != source.node { - return Err(TesterError::RejectForeign.into()); + return Err(tt::TesterError::RejectForeign.into()); } match message { wit::Message::Response(_) => { - return Err(TesterError::UnexpectedResponse.into()); + return Err(tt::TesterError::UnexpectedResponse.into()); }, - wit::Message::Request(wit::Request { ipc, .. }) => { - match serde_json::from_slice(&ipc)? { - TesterRequest::Run => { + wit::Message::Request(wit::Request { ref ipc, .. }) => { + match serde_json::from_slice(ipc)? { + tt::TesterRequest::Run => { wit::print_to_terminal(0, "test_runner: got Run"); let (_, response) = Request::new() @@ -114,19 +82,23 @@ fn handle_message (our: &Address) -> anyhow::Result<()> { .send_and_await_response(5)??; let wit::Message::Response((response, _)) = response else { panic!("") }; - let TesterResponse::Pass = serde_json::from_slice(&response.ipc)? else { - return Err(anyhow::anyhow!("{} FAIL", child)) - }; + match serde_json::from_slice(&response.ipc)? { + tt::TesterResponse::Pass => {}, + tt::TesterResponse::GetFullMessage(_) => {}, + tt::TesterResponse::Fail { test, file, line, column } => { + fail!(test, file, line, column); + }, + } } wit::print_to_terminal(0, &format!("test_runner: done running {:?}", children)); Response::new() - .ipc_bytes(serde_json::to_vec(&TesterResponse::Pass).unwrap()) + .ipc_bytes(serde_json::to_vec(&tt::TesterResponse::Pass).unwrap()) .send() .unwrap(); }, - TesterRequest::KernelMessage(_) | TesterRequest::GetFullMessage(_) => { unimplemented!() }, + tt::TesterRequest::KernelMessage(_) | tt::TesterRequest::GetFullMessage(_) => { unimplemented!() }, } Ok(()) }, @@ -140,17 +112,6 @@ impl Guest for Component { let our = Address::from_str(&our).unwrap(); - // orchestrate tests using external scripts - // -> must give drive cap to rpc - let drive_cap = wit::get_capability( - &make_vfs_address(&our).unwrap(), - &serde_json::to_string(&serde_json::json!({ - "kind": "write", - "drive": "tester:uqbar", - })).unwrap() - ).unwrap(); - wit::share_capability(&ProcessId::from_str("http_server:sys:uqbar").unwrap(), &drive_cap); - loop { match handle_message(&our) { Ok(()) => {}, @@ -159,10 +120,7 @@ impl Guest for Component { "test_runner: error: {:?}", e, ).as_str()); - Response::new() - .ipc_bytes(serde_json::to_vec(&TesterResponse::Fail).unwrap()) - .send() - .unwrap(); + fail!("test_runner"); }, }; } diff --git a/modules/tester/test_runner/src/tester_types.rs b/modules/tester/test_runner/src/tester_types.rs new file mode 120000 index 00000000..24792c5a --- /dev/null +++ b/modules/tester/test_runner/src/tester_types.rs @@ -0,0 +1 @@ +../../tester_types.rs \ No newline at end of file diff --git a/modules/tester/tester/src/lib.rs b/modules/tester/tester/src/lib.rs index ada4f026..0aa7b68a 100644 --- a/modules/tester/tester/src/lib.rs +++ b/modules/tester/tester/src/lib.rs @@ -7,6 +7,9 @@ use uqbar_process_lib::{Address, ProcessId, Request, Response}; use uqbar_process_lib::kernel_types as kt; use uqbar_process_lib::uqbar::process::standard as wit; +mod tester_types; +use tester_types as tt; + wit_bindgen::generate!({ path: "../../../wit", world: "process", @@ -15,42 +18,7 @@ wit_bindgen::generate!({ }, }); -type Rsvp = Option; - -#[derive(Clone, Debug, Serialize, Deserialize)] -struct KernelMessage { - pub id: u64, - pub source: kt::Address, - pub target: kt::Address, - pub rsvp: Rsvp, - pub message: kt::Message, - pub payload: Option, - pub signed_capabilities: Option>, -} - -#[derive(Debug, Serialize, Deserialize)] -enum TesterRequest { - Run, - KernelMessage(KernelMessage), - GetFullMessage(kt::Message), -} - -#[derive(Debug, Serialize, Deserialize)] -enum TesterResponse { - Pass, - Fail, - GetFullMessage(Option), -} - -#[derive(Debug, Serialize, Deserialize, thiserror::Error)] -enum TesterError { - #[error("RejectForeign")] - RejectForeign, - #[error("UnexpectedResponse")] - UnexpectedResponse, -} - -type Messages = IndexMap; +type Messages = IndexMap; fn make_vfs_address(our: &wit::Address) -> anyhow::Result
{ Ok(wit::Address { @@ -63,29 +31,29 @@ fn handle_message(our: &Address, messages: &mut Messages) -> anyhow::Result<()> let (source, message) = wit::receive().unwrap(); if our.node != source.node { - return Err(TesterError::RejectForeign.into()); + return Err(tt::TesterError::RejectForeign.into()); } match message { wit::Message::Response((wit::Response { ipc, .. }, _)) => { match serde_json::from_slice(&ipc)? { - TesterResponse::Pass | TesterResponse::Fail => { + tt::TesterResponse::Pass | tt::TesterResponse::Fail { .. } => { if (source.process.package_name != "tester") | (source.process.publisher_node != "uqbar") { - return Err(TesterError::UnexpectedResponse.into()); + return Err(tt::TesterError::UnexpectedResponse.into()); } Response::new() .ipc_bytes(ipc) .send() .unwrap(); }, - TesterResponse::GetFullMessage(_) => { unimplemented!() } + tt::TesterResponse::GetFullMessage(_) => { unimplemented!() } } Ok(()) }, wit::Message::Request(wit::Request { ipc, .. }) => { match serde_json::from_slice(&ipc)? { - TesterRequest::Run => { + tt::TesterRequest::Run => { wit::print_to_terminal(0, "tester: got Run"); let child = "/test_runner.wasm"; @@ -108,16 +76,16 @@ fn handle_message(our: &Address, messages: &mut Messages) -> anyhow::Result<()> node: our.node.clone(), process: child_process_id, })? - .ipc_bytes(ipc.clone()) + .ipc_bytes(ipc) .expects_response(15) .send()?; }, - TesterRequest::KernelMessage(kernel_message) => { + tt::TesterRequest::KernelMessage(kernel_message) => { messages.insert(kernel_message.message.clone(), kernel_message); }, - TesterRequest::GetFullMessage(message) => { + tt::TesterRequest::GetFullMessage(message) => { Response::new() - .ipc_bytes(serde_json::to_vec(&TesterResponse::GetFullMessage( + .ipc_bytes(serde_json::to_vec(&tt::TesterResponse::GetFullMessage( match messages.get(&message) { None => None, Some(m) => Some(m.clone()), @@ -159,10 +127,7 @@ impl Guest for Component { "tester: error: {:?}", e, ).as_str()); - Response::new() - .ipc_bytes(serde_json::to_vec(&TesterResponse::Fail).unwrap()) - .send() - .unwrap(); + fail!("tester"); }, }; } diff --git a/modules/tester/tester/src/tester_types.rs b/modules/tester/tester/src/tester_types.rs new file mode 120000 index 00000000..24792c5a --- /dev/null +++ b/modules/tester/tester/src/tester_types.rs @@ -0,0 +1 @@ +../../tester_types.rs \ No newline at end of file diff --git a/modules/tester/tester_types.rs b/modules/tester/tester_types.rs new file mode 100644 index 00000000..3eb99b13 --- /dev/null +++ b/modules/tester/tester_types.rs @@ -0,0 +1,77 @@ +use serde::{Serialize, Deserialize}; + +use uqbar_process_lib::Response; +use uqbar_process_lib::kernel_types as kt; +// use uqbar_process_lib::uqbar::process::standard as wit; + +type Rsvp = Option; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct KernelMessage { + pub id: u64, + pub source: kt::Address, + pub target: kt::Address, + pub rsvp: Rsvp, + pub message: kt::Message, + pub payload: Option, + pub signed_capabilities: Option>, +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum TesterRequest { + Run, + KernelMessage(KernelMessage), + GetFullMessage(kt::Message), +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct TesterFail { + pub test: String, + pub file: String, + pub line: u32, + pub column: u32, +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum TesterResponse { + Pass, + Fail { test: String, file: String, line: u32, column: u32 }, + GetFullMessage(Option), +} + +#[derive(Debug, Serialize, Deserialize, thiserror::Error)] +pub enum TesterError { + #[error("RejectForeign")] + RejectForeign, + #[error("UnexpectedResponse")] + UnexpectedResponse, + #[error("FAIL {test} {message}")] + Fail { test: String, message: String }, +} + +#[macro_export] +macro_rules! fail { + ($test:expr) => { + Response::new() + .ipc_bytes(serde_json::to_vec(&tt::TesterResponse::Fail { + test: $test.into(), + file: file!().into(), + line: line!(), + column: column!(), + }).unwrap()) + .send() + .unwrap(); + }; + ($test:expr, $file:expr, $line:expr, $column:expr) => { + Response::new() + .ipc_bytes(serde_json::to_vec(&tt::TesterResponse::Fail { + test: $test.into(), + file: $file.into(), + line: $line, + column: $column, + }).unwrap()) + .send() + .unwrap(); + panic!(""); + }; +} From fdddd3636db875972effa8dcdcfdd03097683ba1 Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Tue, 28 Nov 2023 20:29:10 -0800 Subject: [PATCH 13/24] add networked testing --- modules/tester/test_runner/src/lib.rs | 2 +- modules/tester/tester/src/lib.rs | 94 ++++++++++++++++++--------- modules/tester/tester_types.rs | 2 +- src/kernel/mod.rs | 61 ++++++++--------- 4 files changed, 97 insertions(+), 62 deletions(-) diff --git a/modules/tester/test_runner/src/lib.rs b/modules/tester/test_runner/src/lib.rs index 12a65832..23fb971e 100644 --- a/modules/tester/test_runner/src/lib.rs +++ b/modules/tester/test_runner/src/lib.rs @@ -36,7 +36,7 @@ fn handle_message(our: &Address) -> anyhow::Result<()> { }, wit::Message::Request(wit::Request { ref ipc, .. }) => { match serde_json::from_slice(ipc)? { - tt::TesterRequest::Run => { + tt::TesterRequest::Run(_) => { wit::print_to_terminal(0, "test_runner: got Run"); let (_, response) = Request::new() diff --git a/modules/tester/tester/src/lib.rs b/modules/tester/tester/src/lib.rs index 0aa7b68a..dbbb2eb9 100644 --- a/modules/tester/tester/src/lib.rs +++ b/modules/tester/tester/src/lib.rs @@ -27,13 +27,13 @@ fn make_vfs_address(our: &wit::Address) -> anyhow::Result
{ }) } -fn handle_message(our: &Address, messages: &mut Messages) -> anyhow::Result<()> { +fn handle_message( + our: &Address, + messages: &mut Messages, + node_names: &mut Vec, +) -> anyhow::Result<()> { let (source, message) = wit::receive().unwrap(); - if our.node != source.node { - return Err(tt::TesterError::RejectForeign.into()); - } - match message { wit::Message::Response((wit::Response { ipc, .. }, _)) => { match serde_json::from_slice(&ipc)? { @@ -53,37 +53,70 @@ fn handle_message(our: &Address, messages: &mut Messages) -> anyhow::Result<()> }, wit::Message::Request(wit::Request { ipc, .. }) => { match serde_json::from_slice(&ipc)? { - tt::TesterRequest::Run => { + tt::TesterRequest::Run(input_node_names) => { wit::print_to_terminal(0, "tester: got Run"); - let child = "/test_runner.wasm"; - let child_process_id = match wit::spawn( - None, - child, - &wit::OnPanic::None, // TODO: notify us - &wit::Capabilities::All, - false, // not public - ) { - Ok(child_process_id) => child_process_id, - Err(e) => { - wit::print_to_terminal(0, &format!("couldn't spawn {}: {}", child, e)); - panic!("couldn't spawn"); // TODO - } - }; + assert!(input_node_names.len() >= 1); + *node_names = input_node_names.clone(); - Request::new() - .target(Address { - node: our.node.clone(), - process: child_process_id, - })? - .ipc_bytes(ipc) - .expects_response(15) - .send()?; + if our.node != node_names[0] { + Response::new() + .ipc_bytes(serde_json::to_vec(&tt::TesterResponse::Pass).unwrap()) + .send() + .unwrap(); + } else { + // we are master node + let child = "/test_runner.wasm"; + let child_process_id = match wit::spawn( + None, + child, + &wit::OnPanic::None, // TODO: notify us + &wit::Capabilities::All, + false, // not public + ) { + Ok(child_process_id) => child_process_id, + Err(e) => { + wit::print_to_terminal(0, &format!("couldn't spawn {}: {}", child, e)); + panic!("couldn't spawn"); // TODO + } + }; + Request::new() + .target(Address { + node: our.node.clone(), + process: child_process_id, + })? + .ipc_bytes(ipc) + .expects_response(15) + .send()?; + } }, tt::TesterRequest::KernelMessage(kernel_message) => { - messages.insert(kernel_message.message.clone(), kernel_message); + wit::print_to_terminal(0, "tester: km"); + // if node_names.len() >= 1 { + // if our.node == node_names[0] { + // // we are master node + // messages.insert( + // kernel_message.message.clone(), + // kernel_message, + // ); + // } else { + // Request::new() + // .target(Address { + // node: node_names[0].clone(), + // process: our.process.clone(), + // })? + // .ipc_bytes(ipc) + // .send()?; + // } + // } }, tt::TesterRequest::GetFullMessage(message) => { + wit::print_to_terminal(0, "tester: gfm"); + assert!(node_names.len() >= 1); + if our.node == node_names[0] { + // TODO + // we are master node + } Response::new() .ipc_bytes(serde_json::to_vec(&tt::TesterResponse::GetFullMessage( match messages.get(&message) { @@ -107,6 +140,7 @@ impl Guest for Component { let our = Address::from_str(&our).unwrap(); let mut messages: Messages = IndexMap::new(); + let mut node_names: Vec = Vec::new(); // orchestrate tests using external scripts // -> must give drive cap to rpc @@ -120,7 +154,7 @@ impl Guest for Component { wit::share_capability(&ProcessId::from_str("http_server:sys:uqbar").unwrap(), &drive_cap); loop { - match handle_message(&our, &mut messages) { + match handle_message(&our, &mut messages, &mut node_names) { Ok(()) => {}, Err(e) => { wit::print_to_terminal(0, format!( diff --git a/modules/tester/tester_types.rs b/modules/tester/tester_types.rs index 3eb99b13..43455aef 100644 --- a/modules/tester/tester_types.rs +++ b/modules/tester/tester_types.rs @@ -19,7 +19,7 @@ pub struct KernelMessage { #[derive(Debug, Serialize, Deserialize)] pub enum TesterRequest { - Run, + Run(Vec), KernelMessage(KernelMessage), GetFullMessage(kt::Message), } diff --git a/src/kernel/mod.rs b/src/kernel/mod.rs index c2a4e9ab..37c796a6 100644 --- a/src/kernel/mod.rs +++ b/src/kernel/mod.rs @@ -2071,36 +2071,37 @@ async fn make_event_loop( ).await; // send every single event to tester - #[cfg(feature = "simulation-mode")] - match senders.get(&tester_process_id) { - None => {} - Some(ProcessSender::Runtime(_)) => {} - Some(ProcessSender::Userspace(sender)) => { - let wrapped_kernel_message = t::KernelMessage { - id: 0, - source: t::Address { - node: our_name.clone(), - process: KERNEL_PROCESS_ID.clone(), - }, - target: t::Address { - node: our_name.clone(), - process: tester_process_id.clone(), - }, - rsvp: None, - message: t::Message::Request(t::Request { - inherit: false, - expects_response: None, - ipc: serde_json::to_vec(&serde_json::json!({ - "KernelMessage": kernel_message, - })).unwrap(), - metadata: None, - }), - payload: None, - signed_capabilities: None, - }; - sender.send(Ok(wrapped_kernel_message)).await.unwrap(); - } - } + // TODO: assess if performance will allow this + // #[cfg(feature = "simulation-mode")] + // match senders.get(&tester_process_id) { + // None => {} + // Some(ProcessSender::Runtime(_)) => {} + // Some(ProcessSender::Userspace(sender)) => { + // let wrapped_kernel_message = t::KernelMessage { + // id: 0, + // source: t::Address { + // node: our_name.clone(), + // process: KERNEL_PROCESS_ID.clone(), + // }, + // target: t::Address { + // node: our_name.clone(), + // process: tester_process_id.clone(), + // }, + // rsvp: None, + // message: t::Message::Request(t::Request { + // inherit: false, + // expects_response: None, + // ipc: serde_json::to_vec(&serde_json::json!({ + // "KernelMessage": kernel_message, + // })).unwrap(), + // metadata: None, + // }), + // payload: None, + // signed_capabilities: None, + // }; + // sender.send(Ok(wrapped_kernel_message)).await.unwrap(); + // } + // } if our_name != kernel_message.target.node { // unrecoverable if fails From af0e4a0e92da51eb9d1e2def7df19947cfe990d0 Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Thu, 30 Nov 2023 11:14:25 -0800 Subject: [PATCH 14/24] add mock networking --- src/http_server/mod.rs | 1 + src/main.rs | 8 +++++++ src/net/mock.rs | 47 ++++++++++++++++++++++++++++++++++++++++++ src/net/mod.rs | 6 ++++++ src/types.rs | 26 +++++++++++++++++++++++ 5 files changed, 88 insertions(+) create mode 100644 src/net/mock.rs diff --git a/src/http_server/mod.rs b/src/http_server/mod.rs index 87f35ec7..2926d5b2 100644 --- a/src/http_server/mod.rs +++ b/src/http_server/mod.rs @@ -20,6 +20,7 @@ use warp::ws::{WebSocket, Ws}; use warp::{Filter, Reply}; mod server_fns; +pub use server_fns::is_port_available; // types and constants type HttpSender = tokio::sync::oneshot::Sender; diff --git a/src/main.rs b/src/main.rs index 6ad967ad..6d3203d9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -282,6 +282,7 @@ async fn main() { vfs_message_sender, encryptor_sender, )); + #[cfg(not(feature = "simulation-mode"))] tasks.spawn(net::networking( our.clone(), our_ip.to_string(), @@ -293,6 +294,13 @@ async fn main() { net_message_receiver, REVEAL_IP, )); + #[cfg(feature = "simulation-mode")] + tasks.spawn(net::mock_client( + args.network_router_port, + our.name.clone(), + kernel_message_sender.clone(), + net_message_receiver, + )); tasks.spawn(filesystem::fs_sender( our.name.clone(), manifest, diff --git a/src/net/mock.rs b/src/net/mock.rs new file mode 100644 index 00000000..4840ea14 --- /dev/null +++ b/src/net/mock.rs @@ -0,0 +1,47 @@ +use futures::{SinkExt, StreamExt}; +use tokio::net::TcpStream; +use tokio::sync::mpsc; +use tokio_tungstenite::{connect_async, tungstenite::protocol::Message::{Binary, Text}, WebSocketStream}; +use url::Url; + +use crate::types; + +type Sender = mpsc::Sender; +type Receiver = mpsc::Receiver; + +pub async fn mock_client( + port: u16, + node_identity: types::NodeId, + send_to_loop: Sender, + mut recv_from_loop: Receiver, +) -> anyhow::Result<()> { + let url = format!("ws://127.0.0.1:{}", port); + + let (ws_stream, _) = connect_async(url).await?; + let (mut send_to_ws, mut recv_from_ws) = ws_stream.split(); + + // Send node identity + send_to_ws.send(Text(node_identity.clone())).await?; + + loop { + tokio::select! { + Some(kernel_message) = recv_from_loop.recv() => { + if kernel_message.target.node != node_identity { + // Serialize and send the message through WebSocket + // println!("{}:mock: outgoing {}\r", node_identity ,kernel_message); + let message = Binary(rmp_serde::to_vec(&kernel_message)?); + send_to_ws.send(message).await?; + } + }, + Some(Ok(message)) = recv_from_ws.next() => { + // Deserialize and forward the message to the loop + // println!("{}:mock: incoming {}\r", node_identity, message); + if let Binary(ref bin) = message { + let kernel_message: types::KernelMessage = rmp_serde::from_slice(bin)?; + send_to_loop.send(kernel_message).await?; + } + }, + } + } +} + diff --git a/src/net/mod.rs b/src/net/mod.rs index 0b473adc..1086c780 100644 --- a/src/net/mod.rs +++ b/src/net/mod.rs @@ -18,6 +18,12 @@ use tokio_tungstenite::{ mod types; mod utils; +// Re-export for testing. +#[cfg(feature = "simulation-mode")] +mod mock; +#[cfg(feature = "simulation-mode")] +pub use mock::mock_client; + // only used in connection initialization, otherwise, nacks and Responses are only used for "timeouts" const TIMEOUT: std::time::Duration = std::time::Duration::from_secs(5); diff --git a/src/types.rs b/src/types.rs index ba4e51d0..6bb40141 100644 --- a/src/types.rs +++ b/src/types.rs @@ -16,6 +16,7 @@ lazy_static::lazy_static! { pub static ref VFS_PROCESS_ID: ProcessId = ProcessId::new(Some("vfs"), "sys", "uqbar"); } +#[cfg(not(feature = "simulation-mode"))] #[derive(Parser, Debug)] /// Uqbar: your p2p personal node integrating cryptocurrency and AI #[command(author, version, about, long_about = None)] @@ -36,6 +37,31 @@ pub struct Args { #[arg(short, long, value_parser)] pub password: Option, } +#[cfg(feature = "simulation-mode")] +#[derive(Parser, Debug)] +/// Uqbar: your p2p personal node integrating cryptocurrency and AI +#[command(author, version, about, long_about = None)] +pub struct Args { + /// Home directory + #[arg(short, long)] + pub home: String, + + /// Ethereum RPC endpoint + #[arg(short, long, default_value_t = String::new())] + pub rpc: String, + + /// First port to try binding + #[arg(long, default_value_t = 8080)] + pub port: u16, + + /// Networking password + #[arg(short, long, value_parser)] + pub password: Option, + + /// Network router port + #[arg(short, long, default_value_t = 9001)] + pub network_router_port: u16, +} // // types shared between kernel and processes. frustratingly, this is an exact copy From be83d47c9de23be1adf9c10b38e7899db6b9e828 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 30 Nov 2023 19:15:03 +0000 Subject: [PATCH 15/24] Format Rust code using rustfmt --- src/net/mock.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/net/mock.rs b/src/net/mock.rs index 4840ea14..6fd747c1 100644 --- a/src/net/mock.rs +++ b/src/net/mock.rs @@ -1,7 +1,11 @@ use futures::{SinkExt, StreamExt}; use tokio::net::TcpStream; use tokio::sync::mpsc; -use tokio_tungstenite::{connect_async, tungstenite::protocol::Message::{Binary, Text}, WebSocketStream}; +use tokio_tungstenite::{ + connect_async, + tungstenite::protocol::Message::{Binary, Text}, + WebSocketStream, +}; use url::Url; use crate::types; @@ -44,4 +48,3 @@ pub async fn mock_client( } } } - From c4a5d4d2e014d1da4d96c224c18442621572cc27 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 01:17:38 +0000 Subject: [PATCH 16/24] Format Rust code using rustfmt --- src/main.rs | 53 +++++++++++++++++++++++++++------------------------- src/types.rs | 2 +- 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/src/main.rs b/src/main.rs index 619d52d7..7015bfb6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -47,19 +47,19 @@ const REVEAL_IP: bool = true; #[tokio::main] async fn main() { -// let matches = Command::new("Uqbar") -// .version("0.3.0") -// .author("Uqbar DAO") -// .about("A General Purpose Sovereign Cloud Computing Platform") -// .arg(arg!([home] "Path to home directory").required(true)) -// .arg(arg!(--rpc "Ethereum RPC endpoint (must be wss://)").required(true)) -// .arg(arg!(--llm "LLM endpoint")) -// .get_matches(); -// let home_directory_path = matches.get_one::("home").unwrap(); -// let rpc_url = matches.get_one::("rpc").unwrap(); -// let llm_url = matches.get_one::("llm"); -// -// <<<<<<< HEAD + // let matches = Command::new("Uqbar") + // .version("0.3.0") + // .author("Uqbar DAO") + // .about("A General Purpose Sovereign Cloud Computing Platform") + // .arg(arg!([home] "Path to home directory").required(true)) + // .arg(arg!(--rpc "Ethereum RPC endpoint (must be wss://)").required(true)) + // .arg(arg!(--llm "LLM endpoint")) + // .get_matches(); + // let home_directory_path = matches.get_one::("home").unwrap(); + // let rpc_url = matches.get_one::("rpc").unwrap(); + // let llm_url = matches.get_one::("llm"); + // + // <<<<<<< HEAD let args = types::Args::parse(); let home_directory_path = &args.home; @@ -69,17 +69,17 @@ async fn main() { // read PKI from websocket endpoint served by public RPC // if you get rate-limited or something, pass in your own RPC as a boot argument let rpc_url = args.rpc; -// ======= -// // create home directory if it does not already exist -// if let Err(e) = fs::create_dir_all(home_directory_path).await { -// panic!("failed to create home directory: {:?}", e); -// } -// -// #[cfg(not(feature = "llm"))] -// if let Some(llm_url) = llm_url { -// panic!("You passed in --llm {:?} but you do not have the llm feature enabled. Please re-run with `--features llm`", llm_url); -// } -// >>>>>>> v0.4.0 + // ======= + // // create home directory if it does not already exist + // if let Err(e) = fs::create_dir_all(home_directory_path).await { + // panic!("failed to create home directory: {:?}", e); + // } + // + // #[cfg(not(feature = "llm"))] + // if let Some(llm_url) = llm_url { + // panic!("You passed in --llm {:?} but you do not have the llm feature enabled. Please re-run with `--features llm`", llm_url); + // } + // >>>>>>> v0.4.0 // kernel receives system messages via this channel, all other modules send messages let (kernel_message_sender, kernel_message_receiver): (MessageSender, MessageReceiver) = @@ -200,7 +200,10 @@ async fn main() { let http_server_port = http::utils::find_open_port(args.port).await.unwrap(); println!("runtime bound port {}\r", http_server_port); - println!("login or register at http://localhost:{}\r", http_server_port); + println!( + "login or register at http://localhost:{}\r", + http_server_port + ); let (our, decoded_keyfile) = match args.password { Some(password) => { match fs::read(format!("{}/.keys", home_directory_path)).await { diff --git a/src/types.rs b/src/types.rs index ea3502ad..4324f7e9 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,5 +1,5 @@ -use clap::Parser; use crate::kernel::process::wit; +use clap::Parser; use ring::signature; use serde::{Deserialize, Serialize}; use std::collections::{HashMap, HashSet}; From 4cb09447938c23f623fff71bbee9b1f29a359258 Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Fri, 1 Dec 2023 13:18:40 -0800 Subject: [PATCH 17/24] add fake nodes --- src/main.rs | 177 +++++++++++++++++++++++++++++++++++---------------- src/types.rs | 22 ++++--- 2 files changed, 134 insertions(+), 65 deletions(-) diff --git a/src/main.rs b/src/main.rs index 7015bfb6..a849783c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,8 @@ use crate::types::*; use anyhow::Result; use clap::Parser; +use ring::rand::SystemRandom; +use ring::signature; use ring::signature::KeyPair; use std::env; use std::sync::Arc; @@ -45,6 +47,56 @@ const VERSION: &str = env!("CARGO_PKG_VERSION"); /// such that only their routers can ever see their physical networking details. const REVEAL_IP: bool = true; +async fn serve_register_fe( + home_directory_path: &str, + our_ip: String, + http_server_port: u16, + rpc_url: String, +) -> (Identity, Keyfile) { + // check if we have keys saved on disk, encrypted + // if so, prompt user for "password" to decrypt with + + // once password is received, use to decrypt local keys file, + // and pass the keys into boot process as is done in registration. + + // NOTE: when we log in, we MUST check the PKI to make sure our + // information matches what we think it should be. this includes + // username, networking key, and routing info. + // if any do not match, we should prompt user to create a "transaction" + // that updates their PKI info on-chain. + let (kill_tx, kill_rx) = oneshot::channel::(); + + let disk_keyfile = match fs::read(format!("{}/.keys", home_directory_path)).await { + Ok(keyfile) => keyfile, + Err(_) => Vec::new(), + }; + + let (tx, mut rx) = mpsc::channel::<(Identity, Keyfile, Vec)>(1); + let (our, decoded_keyfile, encoded_keyfile) = tokio::select! { + _ = register::register(tx, kill_rx, our_ip, http_server_port, rpc_url, disk_keyfile) => { + panic!("registration failed") + } + Some((our, decoded_keyfile, encoded_keyfile)) = rx.recv() => { + (our, decoded_keyfile, encoded_keyfile) + } + }; + + println!( + "saving encrypted networking keys to {}/.keys", + home_directory_path + ); + + fs::write(format!("{}/.keys", home_directory_path), encoded_keyfile) + .await + .unwrap(); + + println!("registration complete!"); + + let _ = kill_tx.send(true); + + (our, decoded_keyfile) +} + #[tokio::main] async fn main() { // let matches = Command::new("Uqbar") @@ -66,6 +118,7 @@ async fn main() { if let Err(e) = fs::create_dir_all(home_directory_path).await { panic!("failed to create home directory: {:?}", e); } + println!("home at {}\r", home_directory_path); // read PKI from websocket endpoint served by public RPC // if you get rate-limited or something, pass in your own RPC as a boot argument let rpc_url = args.rpc; @@ -204,72 +257,91 @@ async fn main() { "login or register at http://localhost:{}\r", http_server_port ); - let (our, decoded_keyfile) = match args.password { - Some(password) => { - match fs::read(format!("{}/.keys", home_directory_path)).await { - Err(e) => panic!("could not read keyfile: {}", e), - Ok(keyfile) => { - match keygen::decode_keyfile(keyfile, &password) { - Err(e) => panic!("could not decode keyfile: {}", e), - Ok(decoded_keyfile) => { - let our = Identity { - name: decoded_keyfile.username.clone(), - networking_key: format!( - "0x{}", - hex::encode( - decoded_keyfile.networking_keypair.public_key().as_ref() - ) - ), - ws_routing: None, // TODO - allowed_routers: decoded_keyfile.routers.clone(), - }; - (our, decoded_keyfile) + #[cfg(not(feature = "simulation-mode"))] + let (our, decoded_keyfile) = serve_register_fe( + &home_directory_path, + our_ip.to_string(), + http_server_port.clone(), + rpc_url.clone(), + ).await; + #[cfg(feature = "simulation-mode")] + let (our, decoded_keyfile) = match args.fake_node_name { + None => { + match args.password { + None => { + serve_register_fe( + &home_directory_path, + our_ip.to_string(), + http_server_port.clone(), + rpc_url.clone(), + ).await + } + Some(password) => { + match fs::read(format!("{}/.keys", home_directory_path)).await { + Err(e) => panic!("could not read keyfile: {}", e), + Ok(keyfile) => { + match keygen::decode_keyfile(keyfile, &password) { + Err(e) => panic!("could not decode keyfile: {}", e), + Ok(decoded_keyfile) => { + let our = Identity { + name: decoded_keyfile.username.clone(), + networking_key: format!( + "0x{}", + hex::encode( + decoded_keyfile.networking_keypair.public_key().as_ref() + ) + ), + ws_routing: None, // TODO + allowed_routers: decoded_keyfile.routers.clone(), + }; + (our, decoded_keyfile) + } + } } } } } } - None => { - // check if we have keys saved on disk, encrypted - // if so, prompt user for "password" to decrypt with + Some(name) => { + let password = match args.password { + None => "123".to_string(), + Some(password) => password.to_string(), + }; + let (pubkey, networking_keypair) = keygen::generate_networking_key(); - // once password is received, use to decrypt local keys file, - // and pass the keys into boot process as is done in registration. + let seed = SystemRandom::new(); + let mut jwt_secret = [0u8, 32]; + ring::rand::SecureRandom::fill(&seed, &mut jwt_secret).unwrap(); - // NOTE: when we log in, we MUST check the PKI to make sure our - // information matches what we think it should be. this includes - // username, networking key, and routing info. - // if any do not match, we should prompt user to create a "transaction" - // that updates their PKI info on-chain. - let (kill_tx, kill_rx) = oneshot::channel::(); - - let disk_keyfile = match fs::read(format!("{}/.keys", home_directory_path)).await { - Ok(keyfile) => keyfile, - Err(_) => Vec::new(), + let our = Identity { + name: name.clone(), + networking_key: pubkey, + ws_routing: None, + allowed_routers: vec![], }; - let (tx, mut rx) = mpsc::channel::<(Identity, Keyfile, Vec)>(1); - let (our, decoded_keyfile, encoded_keyfile) = tokio::select! { - _ = register::register(tx, kill_rx, our_ip.to_string(), http_server_port, rpc_url.clone(), disk_keyfile) - => panic!("registration failed"), - (our, decoded_keyfile, encoded_keyfile) = async { - rx.recv().await.expect("registration failed") - } => (our, decoded_keyfile, encoded_keyfile), + let decoded_keyfile = Keyfile { + username: name.clone(), + routers: vec![], + networking_keypair: signature::Ed25519KeyPair::from_pkcs8(networking_keypair.as_ref()) + .unwrap(), + jwt_secret_bytes: jwt_secret.to_vec(), + file_key: keygen::generate_file_key(), }; - println!( - "saving encrypted networking keys to {}/.keys", - home_directory_path + let encoded_keyfile = keygen::encode_keyfile( + password, + name, + decoded_keyfile.routers.clone(), + networking_keypair, + decoded_keyfile.jwt_secret_bytes.clone(), + decoded_keyfile.file_key.clone(), ); fs::write(format!("{}/.keys", home_directory_path), encoded_keyfile) .await .unwrap(); - println!("registration complete!"); - - let _ = kill_tx.send(true); - (our, decoded_keyfile) } }; @@ -327,13 +399,6 @@ async fn main() { .await .expect("fs load failed!"); - let _ = print_sender - .send(Printout { - verbosity: 0, - content: format!("our networking public key: {}", our.networking_key), - }) - .await; - /* * the kernel module will handle our userspace processes and receives * all "messages", the basic message format for uqbar. diff --git a/src/types.rs b/src/types.rs index 4324f7e9..447e168f 100644 --- a/src/types.rs +++ b/src/types.rs @@ -35,9 +35,9 @@ pub struct Args { #[arg(long, default_value_t = 8080)] pub port: u16, - /// Networking password - #[arg(short, long, value_parser)] - pub password: Option, + // /// Networking password + // #[arg(short, long, value_parser)] + // pub password: Option, } #[cfg(not(feature = "simulation-mode"))] #[cfg(feature = "llm")] @@ -57,9 +57,9 @@ pub struct Args { #[arg(long, default_value_t = 8080)] pub port: u16, - /// Networking password - #[arg(short, long, value_parser)] - pub password: Option, + // /// Networking password + // #[arg(short, long, value_parser)] + // pub password: Option, /// LLM endpoint #[arg(required(true), short, long, value_parser)] @@ -82,13 +82,17 @@ pub struct Args { #[arg(long, default_value_t = 8080)] pub port: u16, + /// Network router port + #[arg(short, long, default_value_t = 9001)] + pub network_router_port: u16, + /// Networking password #[arg(short, long, value_parser)] pub password: Option, - /// Network router port - #[arg(short, long, default_value_t = 9001)] - pub network_router_port: u16, + /// Networking password + #[arg(short, long, value_parser)] + pub fake_node_name: Option, } // From f55a703e83eb2288177a631922eb1b4602dc05ea Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 21:19:10 +0000 Subject: [PATCH 18/24] Format Rust code using rustfmt --- src/main.rs | 17 ++++++++++++----- src/types.rs | 2 -- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/main.rs b/src/main.rs index a849783c..1a7ed971 100644 --- a/src/main.rs +++ b/src/main.rs @@ -263,7 +263,8 @@ async fn main() { our_ip.to_string(), http_server_port.clone(), rpc_url.clone(), - ).await; + ) + .await; #[cfg(feature = "simulation-mode")] let (our, decoded_keyfile) = match args.fake_node_name { None => { @@ -274,7 +275,8 @@ async fn main() { our_ip.to_string(), http_server_port.clone(), rpc_url.clone(), - ).await + ) + .await } Some(password) => { match fs::read(format!("{}/.keys", home_directory_path)).await { @@ -288,7 +290,10 @@ async fn main() { networking_key: format!( "0x{}", hex::encode( - decoded_keyfile.networking_keypair.public_key().as_ref() + decoded_keyfile + .networking_keypair + .public_key() + .as_ref() ) ), ws_routing: None, // TODO @@ -323,8 +328,10 @@ async fn main() { let decoded_keyfile = Keyfile { username: name.clone(), routers: vec![], - networking_keypair: signature::Ed25519KeyPair::from_pkcs8(networking_keypair.as_ref()) - .unwrap(), + networking_keypair: signature::Ed25519KeyPair::from_pkcs8( + networking_keypair.as_ref(), + ) + .unwrap(), jwt_secret_bytes: jwt_secret.to_vec(), file_key: keygen::generate_file_key(), }; diff --git a/src/types.rs b/src/types.rs index 447e168f..cdc8a466 100644 --- a/src/types.rs +++ b/src/types.rs @@ -34,7 +34,6 @@ pub struct Args { /// First port to try binding #[arg(long, default_value_t = 8080)] pub port: u16, - // /// Networking password // #[arg(short, long, value_parser)] // pub password: Option, @@ -60,7 +59,6 @@ pub struct Args { // /// Networking password // #[arg(short, long, value_parser)] // pub password: Option, - /// LLM endpoint #[arg(required(true), short, long, value_parser)] pub password: String, From 6ff612c58ef3017eae6da5a6ab2aca71ea9a08aa Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Fri, 1 Dec 2023 13:23:31 -0800 Subject: [PATCH 19/24] remove commented-out code --- src/main.rs | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/src/main.rs b/src/main.rs index 1a7ed971..b5838ba2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -99,19 +99,6 @@ async fn serve_register_fe( #[tokio::main] async fn main() { - // let matches = Command::new("Uqbar") - // .version("0.3.0") - // .author("Uqbar DAO") - // .about("A General Purpose Sovereign Cloud Computing Platform") - // .arg(arg!([home] "Path to home directory").required(true)) - // .arg(arg!(--rpc "Ethereum RPC endpoint (must be wss://)").required(true)) - // .arg(arg!(--llm "LLM endpoint")) - // .get_matches(); - // let home_directory_path = matches.get_one::("home").unwrap(); - // let rpc_url = matches.get_one::("rpc").unwrap(); - // let llm_url = matches.get_one::("llm"); - // - // <<<<<<< HEAD let args = types::Args::parse(); let home_directory_path = &args.home; @@ -122,17 +109,6 @@ async fn main() { // read PKI from websocket endpoint served by public RPC // if you get rate-limited or something, pass in your own RPC as a boot argument let rpc_url = args.rpc; - // ======= - // // create home directory if it does not already exist - // if let Err(e) = fs::create_dir_all(home_directory_path).await { - // panic!("failed to create home directory: {:?}", e); - // } - // - // #[cfg(not(feature = "llm"))] - // if let Some(llm_url) = llm_url { - // panic!("You passed in --llm {:?} but you do not have the llm feature enabled. Please re-run with `--features llm`", llm_url); - // } - // >>>>>>> v0.4.0 // kernel receives system messages via this channel, all other modules send messages let (kernel_message_sender, kernel_message_receiver): (MessageSender, MessageReceiver) = From ba2a379cb76ca0cc776f05abe031095f03c30a5f Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Fri, 1 Dec 2023 14:03:15 -0800 Subject: [PATCH 20/24] make rpc optional in simulation-mode Conflicts: src/main.rs --- src/main.rs | 20 +++++++++++++------- src/types.rs | 4 ++-- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/main.rs b/src/main.rs index b5838ba2..1db60900 100644 --- a/src/main.rs +++ b/src/main.rs @@ -108,6 +108,7 @@ async fn main() { println!("home at {}\r", home_directory_path); // read PKI from websocket endpoint served by public RPC // if you get rate-limited or something, pass in your own RPC as a boot argument + #[cfg(not(feature = "simulation-mode"))] let rpc_url = args.rpc; // kernel receives system messages via this channel, all other modules send messages @@ -246,13 +247,17 @@ async fn main() { None => { match args.password { None => { - serve_register_fe( - &home_directory_path, - our_ip.to_string(), - http_server_port.clone(), - rpc_url.clone(), - ) - .await + match args.rpc { + None => panic!(""), + Some(rpc_url) => { + serve_register_fe( + &home_directory_path, + our_ip.to_string(), + http_server_port.clone(), + rpc_url.clone(), + ).await + } + } } Some(password) => { match fs::read(format!("{}/.keys", home_directory_path)).await { @@ -453,6 +458,7 @@ async fn main() { timer_service_receiver, print_sender.clone(), )); + #[cfg(not(feature = "simulation-mode"))] tasks.spawn(eth_rpc::eth_rpc( our.name.clone(), rpc_url.clone(), diff --git a/src/types.rs b/src/types.rs index cdc8a466..beea4a11 100644 --- a/src/types.rs +++ b/src/types.rs @@ -73,8 +73,8 @@ pub struct Args { pub home: String, /// Ethereum RPC endpoint (must be wss://) - #[arg(required(true), short, long)] - pub rpc: String, + #[arg(short, long)] + pub rpc: Option, /// First port to try binding #[arg(long, default_value_t = 8080)] From e245bc972ec52eecf7bdd8b346cf3f3ae5db7d3e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 22:04:07 +0000 Subject: [PATCH 21/24] Format Rust code using rustfmt --- src/main.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/main.rs b/src/main.rs index 1db60900..8f27d766 100644 --- a/src/main.rs +++ b/src/main.rs @@ -246,19 +246,18 @@ async fn main() { let (our, decoded_keyfile) = match args.fake_node_name { None => { match args.password { - None => { - match args.rpc { - None => panic!(""), - Some(rpc_url) => { - serve_register_fe( - &home_directory_path, - our_ip.to_string(), - http_server_port.clone(), - rpc_url.clone(), - ).await - } + None => match args.rpc { + None => panic!(""), + Some(rpc_url) => { + serve_register_fe( + &home_directory_path, + our_ip.to_string(), + http_server_port.clone(), + rpc_url.clone(), + ) + .await } - } + }, Some(password) => { match fs::read(format!("{}/.keys", home_directory_path)).await { Err(e) => panic!("could not read keyfile: {}", e), From 355befa9a6f89a76e70896c4878b8dced0e60296 Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Mon, 4 Dec 2023 16:05:48 -0800 Subject: [PATCH 22/24] change clap from derive to dot --- src/main.rs | 69 ++++++++++++++++++++++++++++++++++++----------- src/types.rs | 76 ---------------------------------------------------- 2 files changed, 54 insertions(+), 91 deletions(-) diff --git a/src/main.rs b/src/main.rs index 8f27d766..64c1ea78 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,7 @@ use crate::types::*; use anyhow::Result; -use clap::Parser; +use clap::{arg, Command, value_parser}; use ring::rand::SystemRandom; use ring::signature; use ring::signature::KeyPair; @@ -99,17 +99,56 @@ async fn serve_register_fe( #[tokio::main] async fn main() { - let args = types::Args::parse(); + let app = Command::new("Uqbar") + .version(VERSION) + .author("Uqbar DAO: https://github.com/uqbar-dao") + .about("A General Purpose Sovereign Cloud Computing Platform") + .arg(arg!([home] "Path to home directory").required(true)) + .arg(arg!(--port "First port to try binding") + .default_value("8080") + .value_parser(value_parser!(u16)) + ); + + #[cfg(not(feature = "simulation-mode"))] + let app = app + .arg(arg!(--rpc "Ethereum RPC endpoint (must be wss://)").required(true)); + + #[cfg(feature = "simulation-mode")] + let app = app + .arg(arg!(--rpc "Ethereum RPC endpoint (must be wss://)")) + .arg(arg!(--password "Networking password")) + .arg(arg!(--"fake-node-name" "Name of fake node to boot")) + .arg(arg!(--"network-router-port" "Network router port") + .default_value("9001") + .value_parser(value_parser!(u16)) + ); + + #[cfg(feature = "llm")] + let app = app.arg(arg!(--llm "LLM endpoint")); + + let matches = app.get_matches(); + + let home_directory_path = matches.get_one::("home").unwrap(); + let port = matches.get_one::("port").unwrap().clone(); + + #[cfg(not(feature = "simulation-mode"))] + let rpc_url = matches.get_one::("rpc").unwrap(); + + #[cfg(feature = "simulation-mode")] + let (rpc_url, password, network_router_port, fake_node_name) = ( + matches.get_one::("rpc"), + matches.get_one::("password"), + matches.get_one::("network-router-port").unwrap().clone(), + matches.get_one::("fake-node-name"), + ); + + #[cfg(feature = "llm")] + let llm_url = matches.get_one::("llm").unwrap(); - let home_directory_path = &args.home; if let Err(e) = fs::create_dir_all(home_directory_path).await { panic!("failed to create home directory: {:?}", e); } println!("home at {}\r", home_directory_path); - // read PKI from websocket endpoint served by public RPC - // if you get rate-limited or something, pass in your own RPC as a boot argument - #[cfg(not(feature = "simulation-mode"))] - let rpc_url = args.rpc; // kernel receives system messages via this channel, all other modules send messages let (kernel_message_sender, kernel_message_receiver): (MessageSender, MessageReceiver) = @@ -228,7 +267,7 @@ async fn main() { } }; - let http_server_port = http::utils::find_open_port(args.port).await.unwrap(); + let http_server_port = http::utils::find_open_port(port).await.unwrap(); println!("runtime bound port {}\r", http_server_port); println!( "login or register at http://localhost:{}\r", @@ -243,10 +282,10 @@ async fn main() { ) .await; #[cfg(feature = "simulation-mode")] - let (our, decoded_keyfile) = match args.fake_node_name { + let (our, decoded_keyfile) = match fake_node_name { None => { - match args.password { - None => match args.rpc { + match password { + None => match rpc_url { None => panic!(""), Some(rpc_url) => { serve_register_fe( @@ -288,7 +327,7 @@ async fn main() { } } Some(name) => { - let password = match args.password { + let password = match password { None => "123".to_string(), Some(password) => password.to_string(), }; @@ -318,7 +357,7 @@ async fn main() { let encoded_keyfile = keygen::encode_keyfile( password, - name, + name.clone(), decoded_keyfile.routers.clone(), networking_keypair, decoded_keyfile.jwt_secret_bytes.clone(), @@ -423,7 +462,7 @@ async fn main() { )); #[cfg(feature = "simulation-mode")] tasks.spawn(net::mock_client( - args.network_router_port, + network_router_port, our.name.clone(), kernel_message_sender.clone(), net_message_receiver, @@ -479,7 +518,7 @@ async fn main() { our.name.clone(), kernel_message_sender.clone(), llm_receiver, - llm_url.unwrap().to_string(), + llm_url.to_string(), print_sender.clone(), )); } diff --git a/src/types.rs b/src/types.rs index 091cd774..0876e575 100644 --- a/src/types.rs +++ b/src/types.rs @@ -17,82 +17,6 @@ lazy_static::lazy_static! { pub static ref VFS_PROCESS_ID: ProcessId = ProcessId::new(Some("vfs"), "sys", "uqbar"); } -#[cfg(not(feature = "simulation-mode"))] -#[cfg(not(feature = "llm"))] -#[derive(Parser, Debug)] -/// Uqbar: a general-purpose sovereign cloud computing platform -#[command(author, version, about, long_about = None)] -pub struct Args { - /// Path to home directory - #[arg(required(true))] - pub home: String, - - /// Ethereum RPC endpoint (must be wss://) - #[arg(required(true), short, long)] - pub rpc: String, - - /// First port to try binding - #[arg(long, default_value_t = 8080)] - pub port: u16, - // /// Networking password - // #[arg(short, long, value_parser)] - // pub password: Option, -} -#[cfg(not(feature = "simulation-mode"))] -#[cfg(feature = "llm")] -#[derive(Parser, Debug)] -/// Uqbar: a general-purpose sovereign cloud computing platform -#[command(author, version, about, long_about = None)] -pub struct Args { - /// Path to home directory - #[arg(required(true))] - pub home: String, - - /// Ethereum RPC endpoint (must be wss://) - #[arg(required(true), short, long)] - pub rpc: String, - - /// First port to try binding - #[arg(long, default_value_t = 8080)] - pub port: u16, - - // /// Networking password - // #[arg(short, long, value_parser)] - // pub password: Option, - /// LLM endpoint - #[arg(required(true), short, long, value_parser)] - pub password: String, -} -#[cfg(feature = "simulation-mode")] -#[derive(Parser, Debug)] -/// Uqbar: a general-purpose sovereign cloud computing platform -#[command(author, version, about, long_about = None)] -pub struct Args { - /// Path to home directory - #[arg(required(true))] - pub home: String, - - /// Ethereum RPC endpoint (must be wss://) - #[arg(short, long)] - pub rpc: Option, - - /// First port to try binding - #[arg(long, default_value_t = 8080)] - pub port: u16, - - /// Network router port - #[arg(short, long, default_value_t = 9001)] - pub network_router_port: u16, - - /// Networking password - #[arg(short, long, value_parser)] - pub password: Option, - - /// Networking password - #[arg(short, long, value_parser)] - pub fake_node_name: Option, -} - // // types shared between kernel and processes. frustratingly, this is an exact copy // of the types in process_lib From 5aef92cdbc406fa32b984d8d43c59e16d72f9ec7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 5 Dec 2023 00:06:21 +0000 Subject: [PATCH 23/24] Format Rust code using rustfmt --- src/main.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/main.rs b/src/main.rs index 64c1ea78..774e6ca2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,7 @@ use crate::types::*; use anyhow::Result; -use clap::{arg, Command, value_parser}; +use clap::{arg, value_parser, Command}; use ring::rand::SystemRandom; use ring::signature; use ring::signature::KeyPair; @@ -104,23 +104,24 @@ async fn main() { .author("Uqbar DAO: https://github.com/uqbar-dao") .about("A General Purpose Sovereign Cloud Computing Platform") .arg(arg!([home] "Path to home directory").required(true)) - .arg(arg!(--port "First port to try binding") - .default_value("8080") - .value_parser(value_parser!(u16)) + .arg( + arg!(--port "First port to try binding") + .default_value("8080") + .value_parser(value_parser!(u16)), ); #[cfg(not(feature = "simulation-mode"))] - let app = app - .arg(arg!(--rpc "Ethereum RPC endpoint (must be wss://)").required(true)); + let app = app.arg(arg!(--rpc "Ethereum RPC endpoint (must be wss://)").required(true)); #[cfg(feature = "simulation-mode")] let app = app .arg(arg!(--rpc "Ethereum RPC endpoint (must be wss://)")) .arg(arg!(--password "Networking password")) .arg(arg!(--"fake-node-name" "Name of fake node to boot")) - .arg(arg!(--"network-router-port" "Network router port") - .default_value("9001") - .value_parser(value_parser!(u16)) + .arg( + arg!(--"network-router-port" "Network router port") + .default_value("9001") + .value_parser(value_parser!(u16)), ); #[cfg(feature = "llm")] @@ -138,7 +139,10 @@ async fn main() { let (rpc_url, password, network_router_port, fake_node_name) = ( matches.get_one::("rpc"), matches.get_one::("password"), - matches.get_one::("network-router-port").unwrap().clone(), + matches + .get_one::("network-router-port") + .unwrap() + .clone(), matches.get_one::("fake-node-name"), ); From 4844e840c0fe2db3c97889126bd4dc5339f256fc Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Tue, 5 Dec 2023 09:33:15 -0800 Subject: [PATCH 24/24] remove commented-out code the commented-out code relates to a speculative feature that stores ALL KernelMessages in the tester so that tests can access & assert against more than just whatever Response they receive e.g. if a test Request kicks off a chain of 10 Messages, a test might grab those 10 & assert against some subset of them; this is not possible unless we store all KernelMessages somewhere & make them queryable this is a speculative feature in that we don't have a specific usecase in mind for it; it was commented-out for this reason and because it led to significant performance issues (noticeable slowdown of nodes) --- modules/tester/tester/src/lib.rs | 43 ++------------------------------ src/kernel/mod.rs | 33 ------------------------ 2 files changed, 2 insertions(+), 74 deletions(-) diff --git a/modules/tester/tester/src/lib.rs b/modules/tester/tester/src/lib.rs index dbbb2eb9..7c86b5ad 100644 --- a/modules/tester/tester/src/lib.rs +++ b/modules/tester/tester/src/lib.rs @@ -1,6 +1,3 @@ -use serde::{Serialize, Deserialize}; -use std::collections::{HashMap, HashSet}; - use indexmap::map::IndexMap; use uqbar_process_lib::{Address, ProcessId, Request, Response}; @@ -29,7 +26,7 @@ fn make_vfs_address(our: &wit::Address) -> anyhow::Result
{ fn handle_message( our: &Address, - messages: &mut Messages, + _messages: &mut Messages, node_names: &mut Vec, ) -> anyhow::Result<()> { let (source, message) = wit::receive().unwrap(); @@ -90,43 +87,7 @@ fn handle_message( .send()?; } }, - tt::TesterRequest::KernelMessage(kernel_message) => { - wit::print_to_terminal(0, "tester: km"); - // if node_names.len() >= 1 { - // if our.node == node_names[0] { - // // we are master node - // messages.insert( - // kernel_message.message.clone(), - // kernel_message, - // ); - // } else { - // Request::new() - // .target(Address { - // node: node_names[0].clone(), - // process: our.process.clone(), - // })? - // .ipc_bytes(ipc) - // .send()?; - // } - // } - }, - tt::TesterRequest::GetFullMessage(message) => { - wit::print_to_terminal(0, "tester: gfm"); - assert!(node_names.len() >= 1); - if our.node == node_names[0] { - // TODO - // we are master node - } - Response::new() - .ipc_bytes(serde_json::to_vec(&tt::TesterResponse::GetFullMessage( - match messages.get(&message) { - None => None, - Some(m) => Some(m.clone()), - } - )).unwrap()) - .send() - .unwrap(); - }, + tt::TesterRequest::KernelMessage(_) | tt::TesterRequest::GetFullMessage(_) => { unimplemented!() }, } Ok(()) }, diff --git a/src/kernel/mod.rs b/src/kernel/mod.rs index 4475d5ac..67690734 100644 --- a/src/kernel/mod.rs +++ b/src/kernel/mod.rs @@ -928,39 +928,6 @@ pub async fn kernel( } ).await; - // send every single event to tester - // TODO: assess if performance will allow this - // #[cfg(feature = "simulation-mode")] - // match senders.get(&tester_process_id) { - // None => {} - // Some(ProcessSender::Runtime(_)) => {} - // Some(ProcessSender::Userspace(sender)) => { - // let wrapped_kernel_message = t::KernelMessage { - // id: 0, - // source: t::Address { - // node: our_name.clone(), - // process: KERNEL_PROCESS_ID.clone(), - // }, - // target: t::Address { - // node: our_name.clone(), - // process: tester_process_id.clone(), - // }, - // rsvp: None, - // message: t::Message::Request(t::Request { - // inherit: false, - // expects_response: None, - // ipc: serde_json::to_vec(&serde_json::json!({ - // "KernelMessage": kernel_message, - // })).unwrap(), - // metadata: None, - // }), - // payload: None, - // signed_capabilities: None, - // }; - // sender.send(Ok(wrapped_kernel_message)).await.unwrap(); - // } - // } - if our.name != kernel_message.target.node { send_to_net.send(kernel_message).await.expect("fatal: net module died"); } else if kernel_message.target.process.process() == "kernel" {