mirror of
https://github.com/uqbar-dao/nectar.git
synced 2024-12-29 19:41:39 +03:00
terminal: versioned state
This commit is contained in:
parent
9c790103ac
commit
5616efd942
@ -43,15 +43,21 @@ impl std::fmt::Display for ScriptError {
|
||||
impl std::error::Error for ScriptError {}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct TerminalState {
|
||||
#[serde(tag = "version")]
|
||||
enum VersionedState {
|
||||
V1(TerminalStateV1),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct TerminalStateV1 {
|
||||
our: Address,
|
||||
aliases: HashMap<String, ProcessId>,
|
||||
}
|
||||
|
||||
impl TerminalState {
|
||||
impl VersionedState {
|
||||
/// Create a new terminal state with the default system aliases
|
||||
fn new(our: Address) -> Self {
|
||||
Self {
|
||||
Self::V1(TerminalStateV1 {
|
||||
our,
|
||||
aliases: HashMap::from([
|
||||
(
|
||||
@ -103,28 +109,52 @@ impl TerminalState {
|
||||
ProcessId::new(Some("top"), "terminal", "sys"),
|
||||
),
|
||||
]),
|
||||
})
|
||||
}
|
||||
|
||||
fn our(&self) -> &Address {
|
||||
match self {
|
||||
VersionedState::V1(state) => &state.our,
|
||||
}
|
||||
}
|
||||
|
||||
fn aliases(&self) -> &HashMap<String, ProcessId> {
|
||||
match self {
|
||||
VersionedState::V1(state) => &state.aliases,
|
||||
}
|
||||
}
|
||||
|
||||
fn alias_insert(&mut self, alias: String, process: ProcessId) {
|
||||
match self {
|
||||
VersionedState::V1(state) => {
|
||||
state.aliases.insert(alias, process);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn alias_remove(&mut self, alias: &str) {
|
||||
match self {
|
||||
VersionedState::V1(state) => {
|
||||
state.aliases.remove(alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
call_init!(init);
|
||||
fn init(our: Address) {
|
||||
let mut state: TerminalState =
|
||||
match get_typed_state(|bytes| bincode::deserialize::<TerminalState>(bytes)) {
|
||||
let mut state: VersionedState =
|
||||
match get_typed_state(|bytes| bincode::deserialize::<VersionedState>(bytes)) {
|
||||
Some(mut s) => {
|
||||
// **add** the pre-installed scripts to the terminal state
|
||||
// in case new ones have been added or if user has deleted aliases
|
||||
let default_state = TerminalState::new(our);
|
||||
let VersionedState::V1(default_state) = VersionedState::new(our);
|
||||
for (alias, process) in default_state.aliases {
|
||||
s.aliases.insert(alias, process);
|
||||
s.alias_insert(alias, process);
|
||||
}
|
||||
s
|
||||
}
|
||||
None => {
|
||||
let state = TerminalState::new(our);
|
||||
set_state(&bincode::serialize(&state).unwrap());
|
||||
state
|
||||
}
|
||||
None => VersionedState::new(our),
|
||||
};
|
||||
|
||||
loop {
|
||||
@ -143,14 +173,16 @@ fn init(our: Address) {
|
||||
..
|
||||
} => {
|
||||
// this is a message from the runtime terminal, parse as a command
|
||||
if state.our == source {
|
||||
if *state.our() == source {
|
||||
if let Err(e) =
|
||||
parse_command(&mut state, String::from_utf8_lossy(&body).to_string())
|
||||
{
|
||||
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() {
|
||||
} else if state.our().node == source.node
|
||||
&& state.our().package() == source.package()
|
||||
{
|
||||
let Ok(action) = serde_json::from_slice::<TerminalRequest>(&body) else {
|
||||
println!("failed to parse TerminalRequest from {source}");
|
||||
continue;
|
||||
@ -188,15 +220,15 @@ fn init(our: Address) {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_command(state: &mut TerminalState, line: String) -> Result<(), ScriptError> {
|
||||
fn parse_command(state: &mut VersionedState, 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()),
|
||||
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()),
|
||||
Ok(pid) => handle_run(state.our(), &pid, args.to_string()),
|
||||
Err(_) => Err(ScriptError::UnknownName(head.to_string())),
|
||||
},
|
||||
}
|
||||
@ -381,7 +413,7 @@ fn handle_run(our: &Address, process: &ProcessId, args: String) -> Result<(), Sc
|
||||
}
|
||||
|
||||
fn handle_alias_change(
|
||||
state: &mut TerminalState,
|
||||
state: &mut VersionedState,
|
||||
alias: String,
|
||||
process: Option<String>,
|
||||
) -> TerminalResponse {
|
||||
@ -391,12 +423,12 @@ fn handle_alias_change(
|
||||
return TerminalResponse::EditAlias(EditAliasResponse::InvalidProcessId);
|
||||
};
|
||||
println!("alias {alias} set for {process}");
|
||||
state.aliases.insert(alias, parsed_process);
|
||||
state.alias_insert(alias, parsed_process);
|
||||
TerminalResponse::EditAlias(EditAliasResponse::AliasSet)
|
||||
}
|
||||
None => {
|
||||
if state.aliases.contains_key(&alias) {
|
||||
state.aliases.remove(&alias);
|
||||
if state.aliases().contains_key(&alias) {
|
||||
state.alias_remove(&alias);
|
||||
println!("alias {alias} removed");
|
||||
TerminalResponse::EditAlias(EditAliasResponse::AliasRemoved)
|
||||
} else {
|
||||
|
@ -1,5 +1,3 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::kinode::process::tester::{
|
||||
FailResponse, Request as TesterRequest, Response as TesterResponse, RunRequest,
|
||||
};
|
||||
@ -8,6 +6,7 @@ use kinode_process_lib::{
|
||||
await_message, call_init, our_capabilities, println, spawn, vfs, Address, Capability, Message,
|
||||
OnExit, ProcessId, Request, Response,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
|
||||
mod tester_lib;
|
||||
|
||||
@ -21,13 +20,6 @@ wit_bindgen::generate!({
|
||||
const SETUP_PATH: &str = "/tester:sys/setup";
|
||||
const TESTS_PATH: &str = "/tester:sys/tests";
|
||||
|
||||
fn make_vfs_address(our: &Address) -> anyhow::Result<Address> {
|
||||
Ok(Address {
|
||||
node: our.node.clone(),
|
||||
process: "vfs:distro:sys".parse()?,
|
||||
})
|
||||
}
|
||||
|
||||
fn handle_response(message: &Message) -> anyhow::Result<()> {
|
||||
let TesterResponse::Run(_) = message.body().try_into()?;
|
||||
let source = message.source();
|
||||
@ -90,7 +82,7 @@ fn handle_request(
|
||||
let dir_prefix = "tester:sys/tests";
|
||||
|
||||
let response = Request::new()
|
||||
.target(make_vfs_address(&our)?)
|
||||
.target(("our", "vfs", "distro", "sys"))
|
||||
.body(serde_json::to_vec(&vfs::VfsRequest {
|
||||
path: dir_prefix.into(),
|
||||
action: vfs::VfsAction::ReadDir,
|
||||
@ -220,7 +212,7 @@ fn init(our: Address) {
|
||||
let mut node_names: Vec<String> = Vec::new();
|
||||
for path in [SETUP_PATH, TESTS_PATH] {
|
||||
match Request::new()
|
||||
.target(make_vfs_address(&our).unwrap())
|
||||
.target(("our", "vfs", "distro", "sys"))
|
||||
.body(
|
||||
serde_json::to_vec(&vfs::VfsRequest {
|
||||
path: path.into(),
|
||||
@ -271,7 +263,7 @@ fn init(our: Address) {
|
||||
match handle_message(&our, &mut node_names) {
|
||||
Ok(()) => {}
|
||||
Err(e) => {
|
||||
println!("tester: error: {:?}", e,);
|
||||
println!("tester: error: {e:?}");
|
||||
fail!("tester");
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user