scripts: switch to use script! macro, clean up

This commit is contained in:
dr-frmr 2024-08-07 17:46:37 +03:00
parent fd8c97624e
commit a25b0f6204
No known key found for this signature in database
16 changed files with 363 additions and 437 deletions

36
Cargo.lock generated
View File

@ -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]]

View File

@ -130,8 +130,11 @@ alias <shorthand> <full_name>
```
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 <shorthand> <process_id>`: 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 <vfs-file-path>`: print the contents of a file in the terminal.
- Example: `cat /terminal:sys/pkg/scripts.json`
- `echo <text>`: 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 <namehash>`: 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 <name>`: print the peer's PKI info, if it exists.
- `peers`: print the peers the node currently hold connections with.

View File

@ -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] = &[

View File

@ -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::<State>(&body) else {
return "failed to deserialize state".to_string();
};
let state = serde_json::from_slice::<State>(&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::<Vec<_>>();
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 ")
);
)
}

View File

@ -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 <alias_name> <process_id>";
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 <alias_name> <process_id>");
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::<ProcessId>() {
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()
}

View File

@ -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 <file_path>";
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 <file_path>");
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}"),
}
}

View File

@ -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
}

View File

@ -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 <node_id> <message>";
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 <node_id> <message>");
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")
}
},
}

View File

@ -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::<KernelResponse>(&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::<usize>(),
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#"
.`
`@@,, ,* {}

View File

@ -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::<ProcessId>() {
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::<ProcessId>() {
Ok(id) => id,
Err(_) => {
println!("invalid process id");
return;
return "Invalid process ID.\n\x1b[1mUsage:\x1b[0m kill <process_id>".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::<KernelResponse>(&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}")
}

View File

@ -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 <target> <body> [-a <await_time>]");
return;
const USAGE: &str = "\x1b[1mUsage:\x1b[0m m <target> <body> [-a <await_time>]";
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<String> = re
.find_iter(body_string.as_str())
let mut args: Vec<String> = 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::<String>("target") else {
println!("no target");
return;
return format!("No target given.\n{USAGE}");
};
let Ok(target) = target.parse::<Address>() else {
println!("invalid address: \"{target}\"");
return;
return format!("Invalid address: \"{target}\"\n{USAGE}");
};
let Some(body) = parsed.get_one::<String>("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::<u64>("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()
}
}
}

View File

@ -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}")
}

View File

@ -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}"),
}
}

View File

@ -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::<Vec<_>>()
.join("\n");
println!("identities of current connected peers:\n{identities}");
format!("identities of current connected peers:\n{identities}")
}

View File

@ -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<String, ProcessId>,
}
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::<ProcessId>() {
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::<ProcessId>() {
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<kt::Capability> = vec![];
let mut requested_caps: HashSet<kt::Capability> = 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::<ProcessId>() {
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::<ProcessId>()
{
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<ProcessId>,
) -> anyhow::Result<()> {
fn handle_alias_change(state: &mut TerminalState, alias: String, process: Option<ProcessId>) {
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<kt::DotScriptsEntry> {
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::<HashMap<String, kt::DotScriptsEntry>>(&dot_scripts)?;
fn get_entry(process: &ProcessId) -> Result<kt::DotScriptsEntry, ScriptError> {
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::<HashMap<String, kt::DotScriptsEntry>>(&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())
}

View File

@ -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 <show-caps>] <- to view all processes
\ntop <process_id> [-c <show-caps>] <- 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::<ProcessId>());
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::<KernelResponse>(&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::<Vec<_>>()
.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")
}
}
}