From a25b0f62044b779773bd95cc722d71496892e487 Mon Sep 17 00:00:00 2001 From: dr-frmr Date: Wed, 7 Aug 2024 17:46:37 +0300 Subject: [PATCH] scripts: switch to use `script!` macro, clean up --- Cargo.lock | 36 +- README.md | 7 +- kinode/packages/homepage/homepage/src/lib.rs | 2 +- kinode/packages/kns_indexer/state/src/lib.rs | 19 +- kinode/packages/terminal/alias/src/lib.rs | 40 +- kinode/packages/terminal/cat/src/lib.rs | 46 +-- kinode/packages/terminal/echo/src/lib.rs | 16 +- kinode/packages/terminal/hi/src/lib.rs | 40 +- kinode/packages/terminal/kfetch/src/lib.rs | 39 +- kinode/packages/terminal/kill/src/lib.rs | 38 +- kinode/packages/terminal/m/src/lib.rs | 54 ++- .../terminal/net_diagnostics/src/lib.rs | 14 +- kinode/packages/terminal/peer/src/lib.rs | 30 +- kinode/packages/terminal/peers/src/lib.rs | 16 +- kinode/packages/terminal/terminal/src/lib.rs | 355 ++++++++++-------- kinode/packages/terminal/top/src/lib.rs | 48 +-- 16 files changed, 363 insertions(+), 437 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 684b0e50..0b2355fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -385,9 +385,9 @@ dependencies = [ [[package]] name = "alloy-rlp" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a43b18702501396fa9bcdeecd533bc85fac75150d308fc0f6800a01e6234a003" +checksum = "26154390b1d205a4a7ac7352aa2eb4f81f391399d4e2f546fb81a2f8bb383f62" dependencies = [ "alloy-rlp-derive", "arrayvec", @@ -396,9 +396,9 @@ dependencies = [ [[package]] name = "alloy-rlp-derive" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83524c1f6162fcb5b0decf775498a125066c86dda6066ed609531b0e912f85a" +checksum = "4d0f2d905ebd295e7effec65e5f6868d153936130ae718352771de3e7d03c75c" dependencies = [ "proc-macro2", "quote", @@ -1294,9 +1294,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" +checksum = "504bdec147f2cc13c8b57ed9401fd8a147cc66b67ad5cb241394244f2c947549" dependencies = [ "jobserver", "libc", @@ -2881,9 +2881,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" +checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" dependencies = [ "bytes", "futures-channel", @@ -3192,9 +3192,9 @@ dependencies = [ [[package]] name = "keccak-asm" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47a3633291834c4fbebf8673acbc1b04ec9d151418ff9b8e26dcd79129928758" +checksum = "422fbc7ff2f2f5bdffeb07718e5a5324dca72b0c9293d50df4026652385e3314" dependencies = [ "digest 0.10.7", "sha3-asm", @@ -3311,7 +3311,7 @@ dependencies = [ [[package]] name = "kinode_process_lib" version = "0.9.0" -source = "git+https://github.com/kinode-dao/process_lib?branch=develop#6edbf78bbdbd1ba6a755f1888ba78b9144ed4ff8" +source = "git+https://github.com/kinode-dao/process_lib?branch=develop#170f199effb71e322046776641261fcb1a43067e" dependencies = [ "alloy", "alloy-primitives", @@ -4888,9 +4888,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" +checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" [[package]] name = "rustls-webpki" @@ -5126,9 +5126,9 @@ dependencies = [ [[package]] name = "sha3-asm" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9b57fd861253bff08bb1919e995f90ba8f4889de2726091c8876f3a4e823b40" +checksum = "57d79b758b7cb2085612b11a235055e485605a5103faccdd633f35bd7aee69dd" dependencies = [ "cc", "cfg-if", @@ -5468,15 +5468,15 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tempfile" -version = "3.11.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", "fastrand", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] diff --git a/README.md b/README.md index 5761e4f9..38340ec0 100644 --- a/README.md +++ b/README.md @@ -130,8 +130,11 @@ alias ``` Subsequent use of the shorthand will then be interpolated as the process ID. -A list of the other terminal scripts included in this distro: +A list of the terminal scripts included in this distro: +- `alias `: create an alias for a script. + - Example: `alias get_block get_block:kns_indexer:sys` + - note: all of these listed commands are just default aliases for terminal scripts. - `cat `: print the contents of a file in the terminal. - Example: `cat /terminal:sys/pkg/scripts.json` - `echo `: print text to the terminal. @@ -145,8 +148,6 @@ A list of the other terminal scripts included in this distro: - Example: `m our@eth:distro:sys "SetPublic" -a 5` - the '-a' flag is used to expect a response with a given timeout - `our` will always be interpolated by the system as your node's name -- `namehash_to_name `: print the name of a node given its namehash, if we have it indexed. Namehashes are used in the onchain PKI data structure. - - Example: `namehash_to_name 0x46dc6209a66b3a0ef4b72f5d26c0e81c77c7ac146a62e96babf1224484b46fa9` - `net_diagnostics`: print some useful networking diagnostic data. - `peer `: print the peer's PKI info, if it exists. - `peers`: print the peers the node currently hold connections with. diff --git a/kinode/packages/homepage/homepage/src/lib.rs b/kinode/packages/homepage/homepage/src/lib.rs index 96fd0aff..c5a15f63 100644 --- a/kinode/packages/homepage/homepage/src/lib.rs +++ b/kinode/packages/homepage/homepage/src/lib.rs @@ -6,7 +6,7 @@ use kinode_process_lib::{ use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; -/// Fetching OS version from main package.. LMK if there's a better way... +/// Fetching OS version from main package const CARGO_TOML: &str = include_str!("../../../../Cargo.toml"); const DEFAULT_FAVES: &[&str] = &[ diff --git a/kinode/packages/kns_indexer/state/src/lib.rs b/kinode/packages/kns_indexer/state/src/lib.rs index 212ba4a1..ecb60e4f 100644 --- a/kinode/packages/kns_indexer/state/src/lib.rs +++ b/kinode/packages/kns_indexer/state/src/lib.rs @@ -1,4 +1,4 @@ -use kinode_process_lib::{call_init, eth, net, println, Address, Message, Request}; +use kinode_process_lib::{eth, net, script, Address, Message, Request}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; @@ -22,8 +22,10 @@ struct State { last_block: u64, } -call_init!(init); -fn init(_our: Address) { +script!(init); +fn init(_our: Address, _args: String) -> String { + // we don't take any args + let Ok(Message::Response { body, .. }) = Request::to(("our", "kns_indexer", "kns_indexer", "sys")) .body( @@ -39,19 +41,20 @@ fn init(_our: Address) { .send_and_await_response(10) .unwrap() else { - println!("failed to get state from kns_indexer"); - return; + return "failed to get state from kns_indexer".to_string(); + }; + let Ok(state) = serde_json::from_slice::(&body) else { + return "failed to deserialize state".to_string(); }; - let state = serde_json::from_slice::(&body).expect("failed to deserialize state"); // can change later, but for now, just print every known node name let mut names = state.names.values().map(AsRef::as_ref).collect::>(); names.sort(); - println!( + format!( "\nrunning on chain id {}\nCA: {}\n{} known nodes as of block {}\n {}", state.chain_id, state.contract_address, names.len(), state.last_block, names.join("\n ") - ); + ) } diff --git a/kinode/packages/terminal/alias/src/lib.rs b/kinode/packages/terminal/alias/src/lib.rs index 706db263..5f8079e8 100644 --- a/kinode/packages/terminal/alias/src/lib.rs +++ b/kinode/packages/terminal/alias/src/lib.rs @@ -1,6 +1,4 @@ -use kinode_process_lib::{ - await_next_message_body, call_init, println, Address, ProcessId, Request, -}; +use kinode_process_lib::{script, Address, ProcessId, Request}; use serde::{Deserialize, Serialize}; wit_bindgen::generate!({ @@ -16,30 +14,22 @@ enum TerminalAction { }, } -call_init!(init); -fn init(_our: Address) { - let Ok(args) = await_next_message_body() else { - println!("failed to get args"); - return; - }; +const USAGE: &str = "\x1b[1mUsage:\x1b[0m alias "; - let line = String::from_utf8(args).unwrap_or("error".into()); - if line.is_empty() { - println!("Change alias for a process"); - println!("\x1b[1mUsage:\x1b[0m alias "); - return; +script!(init); +fn init(_our: Address, args: String) -> String { + if args.is_empty() { + return format!("Change alias for a process.\n{USAGE}"); } - let (alias, process) = line.split_once(" ").unwrap_or((&line, "")); + let (alias, process) = args.split_once(" ").unwrap_or((&args, "")); if alias.is_empty() { - println!("no alias given"); - return; + return format!("No alias given.\n{USAGE}"); } if process.is_empty() { - let _ = Request::new() - .target(("our", "terminal", "terminal", "sys")) + Request::to(("our", "terminal", "terminal", "sys")) .body( serde_json::to_vec(&TerminalAction::EditAlias { alias: alias.to_string(), @@ -47,12 +37,12 @@ fn init(_our: Address) { }) .unwrap(), ) - .send(); + .send() + .unwrap(); } else { match process.parse::() { Ok(process) => { - let _ = Request::new() - .target(("our", "terminal", "terminal", "sys")) + Request::to(("our", "terminal", "terminal", "sys")) .body( serde_json::to_vec(&TerminalAction::EditAlias { alias: alias.to_string(), @@ -60,11 +50,13 @@ fn init(_our: Address) { }) .unwrap(), ) - .send(); + .send() + .unwrap(); } Err(_) => { - println!("invalid process id"); + return format!("Invalid process ID.\n{USAGE}"); } } } + "alias set".to_string() } diff --git a/kinode/packages/terminal/cat/src/lib.rs b/kinode/packages/terminal/cat/src/lib.rs index 5fb508ee..5c6f3ae5 100644 --- a/kinode/packages/terminal/cat/src/lib.rs +++ b/kinode/packages/terminal/cat/src/lib.rs @@ -1,48 +1,20 @@ -use kinode_process_lib::{ - await_next_message_body, call_init, get_blob, println, vfs, Address, Request, -}; +use kinode_process_lib::{println, script, vfs, Address}; wit_bindgen::generate!({ path: "target/wit", world: "process-v0", }); -call_init!(init); -fn init(_our: Address) { - let Ok(args) = await_next_message_body() else { - println!("failed to get args"); - return; - }; +const USAGE: &str = "\x1b[1mUsage:\x1b[0m cat "; - let Ok(file_path) = String::from_utf8(args) else { - println!("argument must be a single string"); - return; - }; - - if file_path.is_empty() { - println!("Print the contents of a file to the terminal"); - println!("\x1b[1mUsage:\x1b[0m cat "); - return; +script!(init); +fn init(_our: Address, args: String) -> String { + if args.is_empty() { + return format!("Print the contents of a file to the terminal.\n{USAGE}"); } - Request::new() - .target(("our", "vfs", "distro", "sys")) - .body( - serde_json::to_vec(&vfs::VfsRequest { - path: file_path.clone(), - action: vfs::VfsAction::Read, - }) - .unwrap(), - ) - .send_and_await_response(5) - .unwrap() - .unwrap(); - let Some(blob) = get_blob() else { - println!("no file found at {}", file_path); - return; - }; - match String::from_utf8(blob.bytes) { - Ok(s) => println!("{s}"), - Err(_e) => println!("error: file at {file_path} could not be parsed as utf-8 string!"), + match vfs::File::new(&args, 5).read() { + Ok(data) => String::from_utf8_lossy(&data).to_string(), + Err(_) => format!("failed to read file {args} from VFS.\n{USAGE}"), } } diff --git a/kinode/packages/terminal/echo/src/lib.rs b/kinode/packages/terminal/echo/src/lib.rs index 5bcf753e..e429f9ff 100644 --- a/kinode/packages/terminal/echo/src/lib.rs +++ b/kinode/packages/terminal/echo/src/lib.rs @@ -1,19 +1,11 @@ -use kinode_process_lib::{await_next_message_body, call_init, println, Address}; +use kinode_process_lib::{script, Address}; wit_bindgen::generate!({ path: "target/wit", world: "process-v0", }); -call_init!(init); -fn init(_our: Address) { - let Ok(args) = await_next_message_body() else { - println!("failed to get args"); - return; - }; - - match String::from_utf8(args.clone()) { - Ok(s) => println!("{}", s), - Err(_) => println!("{:?}", args), - } +script!(init); +fn init(_our: Address, args: String) -> String { + args } diff --git a/kinode/packages/terminal/hi/src/lib.rs b/kinode/packages/terminal/hi/src/lib.rs index fd64bcfd..144a1881 100644 --- a/kinode/packages/terminal/hi/src/lib.rs +++ b/kinode/packages/terminal/hi/src/lib.rs @@ -1,53 +1,41 @@ -use kinode_process_lib::{ - await_next_message_body, call_init, println, Address, Request, SendError, SendErrorKind, -}; +use kinode_process_lib::{script, Address, Request, SendError, SendErrorKind}; wit_bindgen::generate!({ path: "target/wit", world: "process-v0", }); -call_init!(init); -fn init(our: Address) { - let Ok(args) = await_next_message_body() else { - println!("failed to get args"); - return; - }; +const USAGE: &str = "\x1b[1mUsage:\x1b[0m hi "; - let tail = String::from_utf8(args).unwrap(); - if tail.is_empty() { - println!("Send a Message to another node's terminal"); - println!("\x1b[1mUsage:\x1b[0m hi "); - return; +script!(init); +fn init(our: Address, args: String) -> String { + if args.is_empty() { + return format!("Send a text message to another node's terminal.\n{USAGE}"); } - let (node_id, message) = match tail.split_once(" ") { + let (node_id, message) = match args.split_once(" ") { Some((s, t)) => (s, t), - None => { - println!("invalid command, please provide a message"); - return; - } + None => return format!("Not enough arguments given.\n{USAGE}"), }; let node_id = if node_id == "our" { &our.node } else { node_id }; - match Request::new() - .target((node_id, "net", "distro", "sys")) + match Request::to((node_id, "net", "distro", "sys")) .body(message) - .send_and_await_response(5) + .send_and_await_response(10) .unwrap() { Ok(msg) => { if let Ok(txt) = std::str::from_utf8(&msg.body()) { - println!("response from {node_id}: {txt}"); + format!("response from {node_id}: {txt}") } else { - println!("response from {node_id}: {:?}", msg.body()); + format!("malformed response from {node_id}") } } Err(SendError { kind, .. }) => match kind { SendErrorKind::Timeout => { - println!("message to {node_id} timed out"); + format!("message to {node_id} timed out") } SendErrorKind::Offline => { - println!("{node_id} is offline or does not exist"); + format!("{node_id} is offline or does not exist") } }, } diff --git a/kinode/packages/terminal/kfetch/src/lib.rs b/kinode/packages/terminal/kfetch/src/lib.rs index ab6ef197..b92f4be0 100644 --- a/kinode/packages/terminal/kfetch/src/lib.rs +++ b/kinode/packages/terminal/kfetch/src/lib.rs @@ -1,10 +1,10 @@ use kinode_process_lib::kernel_types::{ KernelCommand, KernelPrint, KernelPrintResponse, KernelResponse, }; -use kinode_process_lib::{call_init, eth, net, println, Address, Message, Request}; +use kinode_process_lib::{eth, net, println, script, Address, Message, Request}; use std::collections::HashSet; -/// Fetching OS version from main package.. LMK if there's a better way... +/// Fetching OS version from main package const CARGO_TOML: &str = include_str!("../../../../Cargo.toml"); wit_bindgen::generate!({ @@ -12,19 +12,18 @@ wit_bindgen::generate!({ world: "process-v0", }); -call_init!(init); -fn init(our: Address) { +script!(init); +/// no args taken +fn init(our: Address, _args: String) -> String { // get identity let Ok(Ok(Message::Response { body, .. })) = Request::to(("our", "net", "distro", "sys")) .body(rmp_serde::to_vec(&net::NetAction::GetPeer(our.node.clone())).unwrap()) .send_and_await_response(60) else { - println!("failed to get response from net"); - return; + return "failed to get response from net".to_string(); }; let Ok(net::NetResponse::Peer(Some(our_id))) = rmp_serde::from_slice(&body) else { - println!("got malformed response from net"); - return; + return "got malformed response from net".to_string(); }; // get eth providers @@ -34,12 +33,10 @@ fn init(our: Address) { .send_and_await_response(60) .unwrap() else { - println!("failed to get response from eth"); - return; + return "failed to get response from eth".to_string(); }; let Ok(eth::EthConfigResponse::Providers(providers)) = serde_json::from_slice(&body) else { - println!("failed to parse eth response"); - return; + return "failed to parse eth response".to_string(); }; // get eth subs @@ -49,16 +46,14 @@ fn init(our: Address) { .send_and_await_response(60) .unwrap() else { - println!("failed to get response from eth"); - return; + return "failed to get response from eth".to_string(); }; let Ok(eth::EthConfigResponse::State { active_subscriptions, outstanding_requests, }) = serde_json::from_slice(&body) else { - println!("failed to parse eth response"); - return; + return "failed to parse eth response".to_string(); }; // get number of processes @@ -68,14 +63,12 @@ fn init(our: Address) { .send_and_await_response(60) .unwrap() else { - println!("failed to get response from kernel"); - return; + return "failed to get response from kernel".to_string(); }; let Ok(KernelResponse::Debug(KernelPrintResponse::ProcessMap(map))) = serde_json::from_slice::(&body) else { - println!("failed to parse kernel response"); - return; + return "failed to parse kernel response".to_string(); }; let num_processes = map.len(); print_bird( @@ -89,7 +82,7 @@ fn init(our: Address) { .sum::(), outstanding_requests.len() as usize, num_processes, - ); + ) } fn print_bird( @@ -99,8 +92,8 @@ fn print_bird( active_subscriptions: usize, outstanding_requests: usize, num_processes: usize, -) { - println!( +) -> String { + format!( r#" .` `@@,, ,* {} diff --git a/kinode/packages/terminal/kill/src/lib.rs b/kinode/packages/terminal/kill/src/lib.rs index ca80ff69..7699f6d0 100644 --- a/kinode/packages/terminal/kill/src/lib.rs +++ b/kinode/packages/terminal/kill/src/lib.rs @@ -1,48 +1,32 @@ use kinode_process_lib::kernel_types::{KernelCommand, KernelResponse}; -use kinode_process_lib::{ - await_next_message_body, call_init, println, Address, Message, ProcessId, Request, -}; +use kinode_process_lib::{script, Address, Message, ProcessId, Request}; wit_bindgen::generate!({ path: "target/wit", world: "process-v0", }); -call_init!(init); -fn init(_our: Address) { - let Ok(args) = await_next_message_body() else { - println!("failed to get args"); - return; - }; - - let Ok(proc_id) = String::from_utf8(args) else { - println!("failed to stringify arguments"); - return; - }; - - let body = match proc_id.parse::() { - Ok(proc_id) => serde_json::to_vec(&KernelCommand::KillProcess(proc_id)).unwrap(), +script!(init); +fn init(_our: Address, args: String) -> String { + let process_id = match args.parse::() { + Ok(id) => id, Err(_) => { - println!("invalid process id"); - return; + return "Invalid process ID.\n\x1b[1mUsage:\x1b[0m kill ".to_string(); } }; - let Ok(Message::Response { body, .. }) = Request::new() - .target(("our", "kernel", "distro", "sys")) - .body(body) + let Ok(Message::Response { body, .. }) = Request::to(("our", "kernel", "distro", "sys")) + .body(serde_json::to_vec(&KernelCommand::KillProcess(process_id)).unwrap()) .send_and_await_response(60) .unwrap() else { - println!("failed to get response from kernel"); - return; + return "failed to get response from kernel".to_string(); }; let Ok(KernelResponse::KilledProcess(proc_id)) = serde_json::from_slice::(&body) else { - println!("failed to parse kernel response"); - return; + return "failed to parse kernel response".to_string(); }; - println!("killed process {}", proc_id); + format!("killed process {proc_id}") } diff --git a/kinode/packages/terminal/m/src/lib.rs b/kinode/packages/terminal/m/src/lib.rs index 2e0a2896..378eea94 100644 --- a/kinode/packages/terminal/m/src/lib.rs +++ b/kinode/packages/terminal/m/src/lib.rs @@ -1,7 +1,5 @@ use clap::{Arg, Command}; -use kinode_process_lib::{ - await_next_message_body, call_init, println, Address, Request, SendErrorKind, -}; +use kinode_process_lib::{println, script, Address, Request, SendErrorKind}; use regex::Regex; wit_bindgen::generate!({ @@ -9,22 +7,17 @@ wit_bindgen::generate!({ world: "process-v0", }); -call_init!(init); -fn init(_our: Address) { - let Ok(body) = await_next_message_body() else { - println!("failed to get args"); - return; - }; - let body_string = String::from_utf8(body).unwrap(); - if body_string.is_empty() { - println!("Send a Request to a Process"); - println!("\x1b[1mUsage:\x1b[0m m [-a ]"); - return; +const USAGE: &str = "\x1b[1mUsage:\x1b[0m m [-a ]"; + +script!(init); +fn init(_our: Address, args: String) -> String { + if args.is_empty() { + return format!("Send a request to a process.\n{USAGE}"); } - let re = Regex::new(r#"'[^']*'|\S+"#).unwrap(); - let mut args: Vec = re - .find_iter(body_string.as_str()) + let mut args: Vec = Regex::new(r#"'[^']*'|\S+"#) + .unwrap() + .find_iter(&args) .map(|mat| { let match_str = mat.as_str(); // Remove the surrounding single quotes for the JSON string @@ -50,44 +43,38 @@ fn init(_our: Address) { ) .try_get_matches_from(args) else { - println!("failed to parse args"); - return; + return format!("Failed to parse args.\n{USAGE}"); }; let Some(target) = parsed.get_one::("target") else { - println!("no target"); - return; + return format!("No target given.\n{USAGE}"); }; let Ok(target) = target.parse::
() else { - println!("invalid address: \"{target}\""); - return; + return format!("Invalid address: \"{target}\"\n{USAGE}"); }; let Some(body) = parsed.get_one::("body") else { - println!("no body"); - return; + return format!("No body given.\n{USAGE}"); }; let req = Request::new().target(target).body(body.as_bytes().to_vec()); match parsed.get_one::("await") { Some(s) => { - println!("awaiting response for {s}s"); + println!("Awaiting response for {s}s"); match req.send_and_await_response(*s).unwrap() { - Ok(res) => { - println!("{}", String::from_utf8(res.body().to_vec()).unwrap()); - } + Ok(res) => String::from_utf8_lossy(res.body()).to_string(), Err(e) => { - println!( + format!( "{}", match e.kind { SendErrorKind::Timeout => - "target did not send Response in time, try increasing the await time", + "Target did not send response in time, try increasing the await time", SendErrorKind::Offline => - "failed to send message because the target is offline", + "Failed to send message because the target is offline", } - ); + ) } } } @@ -95,6 +82,7 @@ fn init(_our: Address) { // still wait for a response, but don't do anything with it // do this so caps checks don't fail let _ = req.send_and_await_response(5).unwrap(); + "".to_string() } } } diff --git a/kinode/packages/terminal/net_diagnostics/src/lib.rs b/kinode/packages/terminal/net_diagnostics/src/lib.rs index 718f1cf3..a360e7b2 100644 --- a/kinode/packages/terminal/net_diagnostics/src/lib.rs +++ b/kinode/packages/terminal/net_diagnostics/src/lib.rs @@ -1,22 +1,20 @@ -use kinode_process_lib::{call_init, net, println, Address, Message, Request}; +use kinode_process_lib::{net, script, Address, Message, Request}; wit_bindgen::generate!({ path: "target/wit", world: "process-v0", }); -call_init!(init); -fn init(_our: Address) { +script!(init); +fn init(_our: Address, _args: String) -> String { let Ok(Ok(Message::Response { body, .. })) = Request::to(("our", "net", "distro", "sys")) .body(rmp_serde::to_vec(&net::NetAction::GetDiagnostics).unwrap()) .send_and_await_response(60) else { - println!("failed to get diagnostics from networking module"); - return; + return "Failed to get diagnostics from networking module".to_string(); }; let Ok(net::NetResponse::Diagnostics(printout)) = rmp_serde::from_slice(&body) else { - println!("got malformed response from networking module"); - return; + return "Got malformed response from networking module".to_string(); }; - println!("\r\n{printout}"); + format!("\r\n{printout}") } diff --git a/kinode/packages/terminal/peer/src/lib.rs b/kinode/packages/terminal/peer/src/lib.rs index 27aa1587..83911c15 100644 --- a/kinode/packages/terminal/peer/src/lib.rs +++ b/kinode/packages/terminal/peer/src/lib.rs @@ -1,38 +1,26 @@ -use kinode_process_lib::{ - await_next_message_body, call_init, net, println, Address, Message, Request, -}; +use kinode_process_lib::{net, script, Address, Message, Request}; wit_bindgen::generate!({ path: "target/wit", world: "process-v0", }); -call_init!(init); -fn init(_our: Address) { - let Ok(args) = await_next_message_body() else { - println!("failed to get args"); - return; - }; - let Ok(name) = String::from_utf8(args) else { - println!("argument must be a string"); - return; - }; +script!(init); +fn init(_our: Address, args: String) -> String { let Ok(Ok(Message::Response { body, .. })) = Request::to(("our", "net", "distro", "sys")) - .body(rmp_serde::to_vec(&net::NetAction::GetPeer(name.clone())).unwrap()) - .send_and_await_response(5) + .body(rmp_serde::to_vec(&net::NetAction::GetPeer(args.clone())).unwrap()) + .send_and_await_response(10) else { - println!("failed to get response from networking module"); - return; + return "Failed to get response from networking module".to_string(); }; let Ok(net::NetResponse::Peer(maybe_peer_id)) = rmp_serde::from_slice(&body) else { - println!("got malformed response from networking module"); - return; + return "Got malformed response from networking module".to_string(); }; match maybe_peer_id { - Some(peer_id) => println!( + Some(peer_id) => format!( "peer identity for {}:\n networking key: {}\n routing: {:?}", peer_id.name, peer_id.networking_key, peer_id.routing ), - None => println!("no PKI entry found with name {name}"), + None => format!("no PKI entry found with name {args}"), } } diff --git a/kinode/packages/terminal/peers/src/lib.rs b/kinode/packages/terminal/peers/src/lib.rs index fbf9f08e..801e7a93 100644 --- a/kinode/packages/terminal/peers/src/lib.rs +++ b/kinode/packages/terminal/peers/src/lib.rs @@ -1,22 +1,20 @@ -use kinode_process_lib::{call_init, net, println, Address, Message, Request}; +use kinode_process_lib::{net, script, Address, Message, Request}; wit_bindgen::generate!({ path: "target/wit", world: "process-v0", }); -call_init!(init); -fn init(_our: Address) { +script!(init); +fn init(_our: Address, _args: String) -> String { let Ok(Ok(Message::Response { body, .. })) = Request::to(("our", "net", "distro", "sys")) .body(rmp_serde::to_vec(&net::NetAction::GetPeers).unwrap()) - .send_and_await_response(5) + .send_and_await_response(10) else { - println!("failed to get peers from networking module"); - return; + return "Failed to get peers from networking module".to_string(); }; let Ok(net::NetResponse::Peers(identities)) = rmp_serde::from_slice(&body) else { - println!("got malformed response from networking module"); - return; + return "Got malformed response from networking module".to_string(); }; let identities = identities .iter() @@ -28,5 +26,5 @@ fn init(_our: Address) { }) .collect::>() .join("\n"); - println!("identities of current connected peers:\n{identities}"); + format!("identities of current connected peers:\n{identities}") } diff --git a/kinode/packages/terminal/terminal/src/lib.rs b/kinode/packages/terminal/terminal/src/lib.rs index 0dcad43d..53a958d2 100644 --- a/kinode/packages/terminal/terminal/src/lib.rs +++ b/kinode/packages/terminal/terminal/src/lib.rs @@ -1,9 +1,6 @@ -use anyhow::anyhow; -use kinode_process_lib::kernel_types as kt; -use kinode_process_lib::kinode::process::standard as wit; use kinode_process_lib::{ - call_init, get_blob, get_typed_state, our_capabilities, println, set_state, vfs, Address, - Capability, ProcessId, Request, + await_message, call_init, get_typed_state, kernel_types as kt, our_capabilities, println, + set_state, vfs, Address, Capability, Message, ProcessId, Request, }; use serde::{Deserialize, Serialize}; use std::collections::{HashMap, HashSet}; @@ -21,28 +18,94 @@ enum TerminalAction { }, } +#[derive(Debug, Serialize, Deserialize)] +enum ScriptError { + UnknownName, + FailedToReadWasm, + NoScriptsManifest, + NoScriptInManifest, + InvalidScriptsManifest, + KernelUnresponsive, +} + +impl std::fmt::Display for ScriptError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match self { + ScriptError::UnknownName => "script not found, either as an alias or process ID", + ScriptError::FailedToReadWasm => "failed to read script Wasm from VFS", + ScriptError::NoScriptsManifest => "no scripts manifest in package", + ScriptError::NoScriptInManifest => "script not in scripts.json file", + ScriptError::InvalidScriptsManifest => "could not parse scripts.json file", + ScriptError::KernelUnresponsive => "kernel unresponsive", + } + ) + } +} + +impl std::error::Error for ScriptError {} + #[derive(Serialize, Deserialize)] struct TerminalState { our: Address, aliases: HashMap, } -fn parse_command(state: &mut TerminalState, line: &str) -> anyhow::Result<()> { - if line.is_empty() { - return Ok(()); +impl TerminalState { + /// Create a new terminal state with the default system aliases + fn new(our: Address) -> Self { + Self { + our, + aliases: HashMap::from([ + ( + "alias".to_string(), + ProcessId::new(Some("alias"), "terminal", "sys"), + ), + ( + "cat".to_string(), + ProcessId::new(Some("cat"), "terminal", "sys"), + ), + ( + "echo".to_string(), + ProcessId::new(Some("echo"), "terminal", "sys"), + ), + ( + "hi".to_string(), + ProcessId::new(Some("hi"), "terminal", "sys"), + ), + ( + "kill".to_string(), + ProcessId::new(Some("kill"), "terminal", "sys"), + ), + ( + "kfetch".to_string(), + ProcessId::new(Some("kfetch"), "terminal", "sys"), + ), + ( + "m".to_string(), + ProcessId::new(Some("m"), "terminal", "sys"), + ), + ( + "net_diagnostics".to_string(), + ProcessId::new(Some("net_diagnostics"), "terminal", "sys"), + ), + ( + "peer".to_string(), + ProcessId::new(Some("peer"), "terminal", "sys"), + ), + ( + "peers".to_string(), + ProcessId::new(Some("peers"), "terminal", "sys"), + ), + ( + "top".to_string(), + ProcessId::new(Some("top"), "terminal", "sys"), + ), + ]), + } } - let (head, args) = line.split_once(" ").unwrap_or((line, "")); - let process = match state.aliases.get(head) { - Some(pid) => pid.clone(), - None => match head.parse::() { - Ok(pid) => pid, - Err(_) => { - return Err(anyhow!("invalid script name")); - } - }, - }; - - handle_run(&state.our, &process, args.to_string()) } call_init!(init); @@ -50,79 +113,28 @@ fn init(our: Address) { let mut state: TerminalState = match get_typed_state(|bytes| bincode::deserialize(bytes)) { Some(s) => s, None => { - let state = TerminalState { - our, - aliases: HashMap::from([ - ( - "alias".to_string(), - ProcessId::new(Some("alias"), "terminal", "sys"), - ), - ( - "cat".to_string(), - ProcessId::new(Some("cat"), "terminal", "sys"), - ), - ( - "echo".to_string(), - ProcessId::new(Some("echo"), "terminal", "sys"), - ), - ( - "hi".to_string(), - ProcessId::new(Some("hi"), "terminal", "sys"), - ), - ( - "kill".to_string(), - ProcessId::new(Some("kill"), "terminal", "sys"), - ), - ( - "kfetch".to_string(), - ProcessId::new(Some("kfetch"), "terminal", "sys"), - ), - ( - "m".to_string(), - ProcessId::new(Some("m"), "terminal", "sys"), - ), - ( - "namehash_to_name".to_string(), - ProcessId::new(Some("namehash_to_name"), "terminal", "sys"), - ), - ( - "net_diagnostics".to_string(), - ProcessId::new(Some("net_diagnostics"), "terminal", "sys"), - ), - ( - "peer".to_string(), - ProcessId::new(Some("peer"), "terminal", "sys"), - ), - ( - "peers".to_string(), - ProcessId::new(Some("peers"), "terminal", "sys"), - ), - ( - "top".to_string(), - ProcessId::new(Some("top"), "terminal", "sys"), - ), - ]), - }; + let state = TerminalState::new(our); set_state(&bincode::serialize(&state).unwrap()); state } }; loop { - let (source, message) = match wit::receive() { - Ok((source, message)) => (source, message), - Err((error, _context)) => { - println!("net error: {:?}!", error.kind); + let message = match await_message() { + Err(e) => { + println!("net error: {e:?}!"); continue; } + Ok(message) => message, }; match message { - wit::Message::Request(wit::Request { body, .. }) => { + Message::Request { source, body, .. } => { + // this is a message from the runtime terminal, parse as a command if state.our == source { - match parse_command(&mut state, std::str::from_utf8(&body).unwrap_or_default()) + if let Err(e) = + parse_command(&mut state, String::from_utf8_lossy(&body).to_string()) { - Ok(()) => continue, - Err(e) => println!("{e}"), + println!("error calling script: {e}"); } // checks for a request from a terminal script (different process, same package) } else if state.our.node == source.node && state.our.package() == source.package() { @@ -132,18 +144,17 @@ fn init(our: Address) { }; match action { TerminalAction::EditAlias { alias, process } => { - match handle_alias_change(&mut state, alias, process) { - Ok(()) => continue, - Err(e) => println!("{e}"), - }; + handle_alias_change(&mut state, alias, process); } } } else { - println!("ignoring message from {source}"); - continue; + kinode_process_lib::print_to_terminal( + 2, + &format!("ignoring message from {source}"), + ); } } - wit::Message::Response((wit::Response { body, .. }, _)) => { + Message::Response { body, .. } => { if let Ok(txt) = std::str::from_utf8(&body) { println!("{txt}"); } else { @@ -154,22 +165,46 @@ fn init(our: Address) { } } -fn handle_run(our: &Address, process: &ProcessId, args: String) -> anyhow::Result<()> { - let drive_path = format!("/{}:{}/pkg", process.package(), process.publisher()); - let Ok(entry) = get_entry(process) else { - return Err(anyhow::anyhow!("script not in scripts.json file")); - }; - let wasm_path = format!("{drive_path}/{}.wasm", process.process()); +fn parse_command(state: &mut TerminalState, line: String) -> Result<(), ScriptError> { + if line.is_empty() { + return Ok(()); + } + let (head, args) = line.split_once(" ").unwrap_or((&line, "")); + match state.aliases.get(head) { + Some(process) => handle_run(&state.our, process, args.to_string()), + None => match head.parse::() { + Ok(pid) => handle_run(&state.our, &pid, args.to_string()), + Err(_) => Err(ScriptError::UnknownName), + }, + } +} + +/// Run a script by loading it from the VFS +fn handle_run(our: &Address, process: &ProcessId, args: String) -> Result<(), ScriptError> { + let entry = get_entry(process)?; + let wasm_path = format!( + "/{}:{}/pkg/{}.wasm", + process.package(), + process.publisher(), + process.process() + ); // all scripts are given random process IDs let process_id = ProcessId::new(None, process.package(), process.publisher()); + // call VFS manually so as not to fetch the blob, instead passing it to kernel request Request::to(("our", "vfs", "distro", "sys")) - .body(serde_json::to_vec(&vfs::VfsRequest { - path: wasm_path.clone(), - action: vfs::VfsAction::Read, - })?) - .send_and_await_response(5)??; + .body( + serde_json::to_vec(&vfs::VfsRequest { + path: wasm_path.clone(), + action: vfs::VfsAction::Read, + }) + .unwrap(), + ) + .send_and_await_response(5) + .unwrap() + .map_err(|_| ScriptError::FailedToReadWasm)?; + // process the caps we are going to grant to other processes let mut granted_caps: Vec<(ProcessId, Capability)> = vec![]; if let Some(to_grant) = &entry.grant_capabilities { @@ -219,32 +254,24 @@ fn handle_run(our: &Address, process: &ProcessId, args: String) -> anyhow::Resul } for (process, cap) in granted_caps.into_iter() { Request::to(("our", "kernel", "distro", "sys")) - .body(serde_json::to_vec(&kt::KernelCommand::GrantCapabilities { - target: process, - capabilities: vec![kt::de_wit_capability(cap)], - })?) - .send()?; + .body( + serde_json::to_vec(&kt::KernelCommand::GrantCapabilities { + target: process, + capabilities: vec![kt::de_wit_capability(cap)], + }) + .unwrap(), + ) + .send() + .unwrap(); } - // inherits the blob from the previous request, `_bytes_response`, - // containing the wasm byte code of the process - Request::to(("our", "kernel", "distro", "sys")) - .body(serde_json::to_vec(&kt::KernelCommand::InitializeProcess { - id: process_id.clone(), - wasm_bytes_handle: wasm_path.clone(), - wit_version: entry.wit_version, - on_exit: kt::OnExit::None, - initial_capabilities: HashSet::new(), - public: entry.public, - })?) - .inherit(true) - .send_and_await_response(5)??; - let mut requested_caps: Vec = vec![]; + + let mut requested_caps: HashSet = HashSet::new(); if let Some(to_request) = &entry.request_capabilities { for value in to_request { match value { serde_json::Value::String(process_name) => { if let Ok(parsed_process_id) = process_name.parse::() { - requested_caps.push(kt::Capability { + requested_caps.insert(kt::Capability { issuer: Address { node: our.node.clone(), process: parsed_process_id.clone(), @@ -261,7 +288,7 @@ fn handle_run(our: &Address, process: &ProcessId, args: String) -> anyhow::Resul .parse::() { if let Some(params) = map.get("params") { - requested_caps.push(kt::Capability { + requested_caps.insert(kt::Capability { issuer: Address { node: our.node.clone(), process: parsed_process_id.clone(), @@ -279,43 +306,58 @@ fn handle_run(our: &Address, process: &ProcessId, args: String) -> anyhow::Resul } } // always give it the cap to message the terminal back - requested_caps.push(kt::de_wit_capability(Capability { + requested_caps.insert(kt::de_wit_capability(Capability { issuer: our.clone(), params: "\"messaging\"".to_string(), })); if entry.request_networking { - requested_caps.push(kt::de_wit_capability(Capability { + requested_caps.insert(kt::de_wit_capability(Capability { issuer: Address::new(&our.node, ("kernel", "distro", "sys")), params: "\"network\"".to_string(), })); } if entry.root { for cap in our_capabilities() { - requested_caps.push(kt::de_wit_capability(cap.clone())); + requested_caps.insert(kt::de_wit_capability(cap)); } } + + // inherits the blob from the previous request to VFS + // containing the wasm byte code of the process Request::to(("our", "kernel", "distro", "sys")) - .body(serde_json::to_vec(&kt::KernelCommand::GrantCapabilities { - target: process_id.clone(), - capabilities: requested_caps, - })?) - .send()?; + .body( + serde_json::to_vec(&kt::KernelCommand::InitializeProcess { + id: process_id.clone(), + wasm_bytes_handle: wasm_path, + wit_version: entry.wit_version, + on_exit: kt::OnExit::None, + initial_capabilities: requested_caps, + public: entry.public, + }) + .unwrap(), + ) + .inherit(true) + .send_and_await_response(5) + .unwrap() + .map_err(|_| ScriptError::KernelUnresponsive)?; + + // run the process Request::to(("our", "kernel", "distro", "sys")) - .body(serde_json::to_vec(&kt::KernelCommand::RunProcess( - process_id.clone(), - ))?) - .send_and_await_response(5)??; + .body(serde_json::to_vec(&kt::KernelCommand::RunProcess(process_id.clone())).unwrap()) + .send_and_await_response(5) + .unwrap() + .map_err(|_| ScriptError::KernelUnresponsive)?; + + // once process is running, send the arguments to it Request::to(("our", process_id)) .body(args.into_bytes()) - .send()?; + .send() + .unwrap(); + Ok(()) } -fn handle_alias_change( - state: &mut TerminalState, - alias: String, - process: Option, -) -> anyhow::Result<()> { +fn handle_alias_change(state: &mut TerminalState, alias: String, process: Option) { match process { Some(process) => { println!("alias {alias} set for {process}"); @@ -330,28 +372,25 @@ fn handle_alias_change( } } } - set_state(&bincode::serialize(&state)?); - Ok(()) + set_state(&bincode::serialize(&state).expect("failed to serialize terminal state")); } -fn get_entry(process: &ProcessId) -> anyhow::Result { - let drive_path = format!("/{}:{}/pkg", process.package(), process.publisher()); - Request::to(("our", "vfs", "distro", "sys")) - .body(serde_json::to_vec(&vfs::VfsRequest { - path: format!("{drive_path}/scripts.json"), - action: vfs::VfsAction::Read, - })?) - .send_and_await_response(5)??; - let Some(blob) = get_blob() else { - return Err(anyhow::anyhow!( - "couldn't find /{}/pkg/scripts.json", - process.package() - )); - }; - let dot_scripts = String::from_utf8(blob.bytes)?; - let dot_scripts = serde_json::from_str::>(&dot_scripts)?; +fn get_entry(process: &ProcessId) -> Result { + let file = vfs::File::new( + format!( + "/{}:{}/pkg/scripts.json", + process.package(), + process.publisher() + ), + 5, + ) + .read() + .map_err(|_| ScriptError::NoScriptsManifest)?; + + let dot_scripts = serde_json::from_slice::>(&file) + .map_err(|_| ScriptError::InvalidScriptsManifest)?; let Some(entry) = dot_scripts.get(&format!("{}.wasm", process.process())) else { - return Err(anyhow::anyhow!("script not in scripts.json file")); + return Err(ScriptError::NoScriptInManifest); }; - Ok(entry.clone()) + Ok(entry.to_owned()) } diff --git a/kinode/packages/terminal/top/src/lib.rs b/kinode/packages/terminal/top/src/lib.rs index 6df53a21..be1aee87 100644 --- a/kinode/packages/terminal/top/src/lib.rs +++ b/kinode/packages/terminal/top/src/lib.rs @@ -2,22 +2,20 @@ use clap::{Arg, Command}; use kinode_process_lib::kernel_types::{ KernelCommand, KernelPrint, KernelPrintResponse, KernelResponse, PersistedProcess, }; -use kinode_process_lib::{ - await_next_message_body, call_init, println, Address, Message, ProcessId, Request, -}; +use kinode_process_lib::{script, Address, Message, ProcessId, Request}; wit_bindgen::generate!({ path: "target/wit", world: "process-v0", }); -call_init!(init); -fn init(_our: Address) { - let Ok(body) = await_next_message_body() else { - println!("failed to get args"); - return; - }; - let body_string = format!("top {}", String::from_utf8(body).unwrap()); +const USAGE: &str = "\x1b[1mUsage:\x1b[0m + \ntop [-c ] <- to view all processes + \ntop [-c ] <- to view one process"; + +script!(init); +fn init(_our: Address, args: String) -> String { + let body_string = format!("top {args}"); let Ok(parsed) = Command::new("top") .disable_help_flag(true) @@ -30,8 +28,7 @@ fn init(_our: Address) { ) .try_get_matches_from(body_string.split_whitespace()) else { - println!("failed to parse args"); - return; + return format!("Failed to parse args.\n{USAGE}"); }; let target = parsed @@ -39,18 +36,14 @@ fn init(_our: Address) { .map(|s| s.parse::()); let show_caps = parsed.get_flag("show-caps"); - let Ok(Message::Response { body, .. }) = Request::new() - .target(("our", "kernel", "distro", "sys")) + let Ok(Message::Response { body, .. }) = Request::to(("our", "kernel", "distro", "sys")) .body(if let Some(target) = &target { match target { Ok(proc_id) => { serde_json::to_vec(&KernelCommand::Debug(KernelPrint::Process(proc_id.clone()))) .unwrap() } - Err(e) => { - println!("invalid process id: {e}"); - return; - } + Err(e) => return format!("invalid process id: {e}\n{USAGE}"), } } else { serde_json::to_vec(&KernelCommand::Debug(KernelPrint::ProcessMap)).unwrap() @@ -58,14 +51,12 @@ fn init(_our: Address) { .send_and_await_response(60) .unwrap() else { - println!("failed to get response from kernel"); - return; + return "Failed to get response from kernel".to_string(); }; let Ok(KernelResponse::Debug(kernel_print_response)) = serde_json::from_slice::(&body) else { - println!("failed to parse kernel response"); - return; + return "Failed to parse kernel response".to_string(); }; match kernel_print_response { @@ -76,27 +67,26 @@ fn init(_our: Address) { .map(|(proc_id, process)| print_process(proc_id, process, show_caps)) .collect::>() .join("\r\n"); - println!("\r\n{printout}\r\n\r\ntop: {len} running processes"); + format!("\r\n{printout}\r\n\r\ntop: {len} running processes") } KernelPrintResponse::Process(process) => match process { None => { - println!( + format!( "process {} not running", target.map_or("(all)".to_string(), |t| t .map(|t| t.to_string()) .unwrap_or_default()) - ); - return; + ) } Some(process) => { - println!( + format!( "{}", print_process(&target.unwrap().unwrap(), &process, show_caps) - ); + ) } }, KernelPrintResponse::HasCap(_) => { - println!("kernel gave wrong kind of response"); + format!("kernel gave wrong kind of response") } } }