From 8438692fd7d24cb8f61b0778955062a0cbfa856d Mon Sep 17 00:00:00 2001 From: Drew Tada Date: Mon, 5 Feb 2024 11:00:03 -0500 Subject: [PATCH 1/6] Capability display update --- src/capability.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/capability.rs b/src/capability.rs index ca0a555..f8e9917 100644 --- a/src/capability.rs +++ b/src/capability.rs @@ -134,7 +134,7 @@ where impl std::fmt::Display for Capability { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}^{}", self.issuer, self.params) + write!(f, "{}({})", self.issuer, self.params) } } From 9e90300cac17e922d76f348fb454b3bd90fa9220 Mon Sep 17 00:00:00 2001 From: Drew Tada Date: Tue, 6 Feb 2024 14:27:25 -0500 Subject: [PATCH 2/6] DropCapabilities added to KernelCommand --- Cargo.lock | 2 +- src/kernel_types.rs | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 7c152e3..1d33eb6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1010,7 +1010,7 @@ dependencies = [ [[package]] name = "kinode_process_lib" -version = "0.5.8" +version = "0.5.9" dependencies = [ "alloy-rpc-types", "anyhow", diff --git a/src/kernel_types.rs b/src/kernel_types.rs index 758af9a..9931440 100644 --- a/src/kernel_types.rs +++ b/src/kernel_types.rs @@ -106,6 +106,11 @@ pub enum KernelCommand { target: ProcessId, capabilities: Vec, }, + /// Drop capabilities. Does nothing if process doesn't have these caps + DropCapabilities { + target: ProcessId, + capabilities: Vec, + }, /// Tell the kernel to run a process that has already been installed. /// TODO: in the future, this command could be extended to allow for /// resource provision. From 9668c820986e32f7b8430648147c2498d5abb9f8 Mon Sep 17 00:00:00 2001 From: Drew Tada Date: Tue, 6 Feb 2024 17:46:14 -0500 Subject: [PATCH 3/6] Capability deserialization working --- Cargo.lock | 2 +- src/capability.rs | 85 ++++++++++++++++------------------------------- 2 files changed, 30 insertions(+), 57 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1d33eb6..7c152e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1010,7 +1010,7 @@ dependencies = [ [[package]] name = "kinode_process_lib" -version = "0.5.9" +version = "0.5.8" dependencies = [ "alloy-rpc-types", "anyhow", diff --git a/src/capability.rs b/src/capability.rs index f8e9917..2f25f7c 100644 --- a/src/capability.rs +++ b/src/capability.rs @@ -1,4 +1,4 @@ -pub use crate::{Address, Capability, ProcessId}; +pub use crate::{Address, Capability}; use serde::{Deserialize, Serialize}; use std::hash::{Hash, Hasher}; @@ -31,54 +31,30 @@ impl Capability { impl std::str::FromStr for Capability { type Err = CapabilityParseError; - /// Attempt to parse a `Capability` from a string. The formatting structure for - /// a Capability is `issuer^params`. - /// TODO not tested - fn from_str(input: &str) -> Result { - // split string on colons into 4 segments, - // first one with @, next 3 with : - let mut name_rest = input.split('@'); - let node = name_rest - .next() - .ok_or(CapabilityParseError::MissingField)? - .to_string(); - let mut param_segments = name_rest - .next() - .ok_or(CapabilityParseError::MissingNodeId)? - .split('^'); - let mut segments = param_segments - .next() - .ok_or(CapabilityParseError::MissingNodeId)? - .split(':'); - let process_name = segments - .next() - .ok_or(CapabilityParseError::MissingField)? - .to_string(); - let package_name = segments - .next() - .ok_or(CapabilityParseError::MissingField)? - .to_string(); - let publisher_node = segments - .next() - .ok_or(CapabilityParseError::MissingField)? - .to_string(); - let params = param_segments - .next() - .ok_or(CapabilityParseError::MissingParams)? - .to_string(); - if segments.next().is_some() { - return Err(CapabilityParseError::TooManyColons); + + fn from_str(s: &str) -> Result { + let end_of_issuer_index = s + .find('(') + .ok_or_else(|| CapabilityParseError::MissingParenthesis)?; + let start_of_params_index = end_of_issuer_index + 1; + let params_end_index = s + .rfind(')') + .ok_or_else(|| CapabilityParseError::MissingParenthesis)?; + + if params_end_index <= start_of_params_index { + return Err(CapabilityParseError::MissingParenthesis); } + + let issuer_str = &s[..end_of_issuer_index]; + let params_str = &s[start_of_params_index..params_end_index]; + + let Ok(issuer) = issuer_str.parse::
() else { + return Err(CapabilityParseError::InvalidAddress); + }; + Ok(Capability { - issuer: Address { - node, - process: ProcessId { - process_name, - package_name, - publisher_node, - }, - }, - params, + issuer, + params: params_str.to_string(), }) } } @@ -141,10 +117,9 @@ impl std::fmt::Display for Capability { /// Error type for parsing an `Address` from a string. #[derive(Debug)] pub enum CapabilityParseError { - TooManyColons, - MissingNodeId, - MissingField, + MissingParenthesis, MissingParams, + InvalidAddress, } impl std::fmt::Display for CapabilityParseError { @@ -153,10 +128,9 @@ impl std::fmt::Display for CapabilityParseError { f, "{}", match self { - CapabilityParseError::TooManyColons => "Too many colons in ProcessId string", - CapabilityParseError::MissingNodeId => "Node ID missing", - CapabilityParseError::MissingField => "Missing field in ProcessId string", + CapabilityParseError::MissingParenthesis => "Missing parenthesis around Capability", CapabilityParseError::MissingParams => "Missing params in Capability string", + CapabilityParseError::InvalidAddress => "Invalid address in Capability string", } ) } @@ -165,10 +139,9 @@ impl std::fmt::Display for CapabilityParseError { impl std::error::Error for CapabilityParseError { fn description(&self) -> &str { match self { - CapabilityParseError::TooManyColons => "Too many colons in ProcessId string", - CapabilityParseError::MissingNodeId => "Node ID missing", - CapabilityParseError::MissingField => "Missing field in ProcessId string", + CapabilityParseError::MissingParenthesis => "Missing parenthesis around Capability", CapabilityParseError::MissingParams => "Missing params in Capability string", + CapabilityParseError::InvalidAddress => "Invalid address in Capability string", } } } From a68f4f6d7cacf8d1b9b409b561ad59114e537865 Mon Sep 17 00:00:00 2001 From: Drew Tada Date: Wed, 7 Feb 2024 18:18:52 -0500 Subject: [PATCH 4/6] incremented crate version --- Cargo.lock | 2 +- Cargo.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7c152e3..56253cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1010,7 +1010,7 @@ dependencies = [ [[package]] name = "kinode_process_lib" -version = "0.5.8" +version = "0.6.0" dependencies = [ "alloy-rpc-types", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index afba26a..d72bafb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,14 +1,14 @@ [package] name = "kinode_process_lib" description = "A library for writing Kinode processes in Rust." -version = "0.5.8" +version = "0.6.0" edition = "2021" license-file = "LICENSE" homepage = "https://kinode.org" repository = "https://github.com/kinode-dao/process_lib" [features] -eth = [ "ethers-core", "alloy-rpc-types" ] +eth = ["ethers-core", "alloy-rpc-types"] [dependencies] alloy-rpc-types = { git = "https://github.com/alloy-rs/alloy.git", rev = "3b1c310", optional = true } From 509b1ed65041762dc6dfa7dd85811b7783c1997c Mon Sep 17 00:00:00 2001 From: Drew Tada Date: Wed, 7 Feb 2024 18:19:10 -0500 Subject: [PATCH 5/6] DotScriptsEntry is Clone --- src/kernel_types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel_types.rs b/src/kernel_types.rs index 9931440..1d73be8 100644 --- a/src/kernel_types.rs +++ b/src/kernel_types.rs @@ -224,7 +224,7 @@ pub struct PackageManifestEntry { } /// the type that gets deserialized from a `scripts.json` object -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct DotScriptsEntry { pub root: bool, pub public: bool, From e8c2cac7c4a4ed7ce3b49717ae3fe0ce4ae708d0 Mon Sep 17 00:00:00 2001 From: Drew Tada Date: Thu, 8 Feb 2024 14:35:34 -0500 Subject: [PATCH 6/6] cap serde fixed --- src/capability.rs | 163 +++++++++++++++++++++++++++------------------- 1 file changed, 97 insertions(+), 66 deletions(-) diff --git a/src/capability.rs b/src/capability.rs index 2f25f7c..d43e4e1 100644 --- a/src/capability.rs +++ b/src/capability.rs @@ -1,5 +1,6 @@ pub use crate::{Address, Capability}; -use serde::{Deserialize, Serialize}; +use serde::de::{self, Deserialize, Deserializer, MapAccess, SeqAccess, Visitor}; +use serde::ser::{Serialize, SerializeStruct}; use std::hash::{Hash, Hasher}; /// Capability is defined in the wit bindings, but constructors and methods here. @@ -29,42 +30,15 @@ impl Capability { } } -impl std::str::FromStr for Capability { - type Err = CapabilityParseError; - - fn from_str(s: &str) -> Result { - let end_of_issuer_index = s - .find('(') - .ok_or_else(|| CapabilityParseError::MissingParenthesis)?; - let start_of_params_index = end_of_issuer_index + 1; - let params_end_index = s - .rfind(')') - .ok_or_else(|| CapabilityParseError::MissingParenthesis)?; - - if params_end_index <= start_of_params_index { - return Err(CapabilityParseError::MissingParenthesis); - } - - let issuer_str = &s[..end_of_issuer_index]; - let params_str = &s[start_of_params_index..params_end_index]; - - let Ok(issuer) = issuer_str.parse::
() else { - return Err(CapabilityParseError::InvalidAddress); - }; - - Ok(Capability { - issuer, - params: params_str.to_string(), - }) - } -} - impl Serialize for Capability { fn serialize(&self, serializer: S) -> Result where S: serde::ser::Serializer, { - format!("{}", self).serialize(serializer) + let mut state = serializer.serialize_struct("Capability", 2)?; + state.serialize_field("issuer", &self.issuer)?; + state.serialize_field("params", &self.params)?; + state.end() } } @@ -73,8 +47,97 @@ impl<'a> Deserialize<'a> for Capability { where D: serde::de::Deserializer<'a>, { - let s = String::deserialize(deserializer)?; - s.parse().map_err(serde::de::Error::custom) + enum Field { + Issuer, + Params, + } + + impl<'de> Deserialize<'de> for Field { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct FieldVisitor; + + impl<'de> Visitor<'de> for FieldVisitor { + type Value = Field; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("`issuer` or `params`") + } + + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + match value { + "issuer" => Ok(Field::Issuer), + "params" => Ok(Field::Params), + _ => Err(de::Error::unknown_field(value, FIELDS)), + } + } + } + + deserializer.deserialize_identifier(FieldVisitor) + } + } + + struct CapabilityVisitor; + + impl<'de> Visitor<'de> for CapabilityVisitor { + type Value = Capability; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("struct Capability") + } + + fn visit_seq(self, mut seq: V) -> Result + where + V: SeqAccess<'de>, + { + let issuer: Address = seq + .next_element()? + .ok_or_else(|| de::Error::invalid_length(0, &self))?; + let params: String = seq + .next_element()? + .ok_or_else(|| de::Error::invalid_length(1, &self))?; + Ok(Capability::new(issuer, params)) + } + + fn visit_map(self, mut map: V) -> Result + where + V: MapAccess<'de>, + { + let mut issuer: Option
= None; + let mut params: Option = None; + while let Some(key) = map.next_key()? { + match key { + Field::Issuer => { + if issuer.is_some() { + return Err(de::Error::duplicate_field("issuer")); + } + issuer = Some(map.next_value()?); + } + Field::Params => { + if params.is_some() { + return Err(de::Error::duplicate_field("params")); + } + params = Some(map.next_value()?); + } + } + } + let issuer: Address = issuer + .ok_or_else(|| de::Error::missing_field("issuer"))? + .into(); + let params: String = params + .ok_or_else(|| de::Error::missing_field("params"))? + .into(); + Ok(Capability::new(issuer, params)) + } + } + + const FIELDS: &'static [&'static str] = &["issuer", "params"]; + deserializer.deserialize_struct("Capability", FIELDS, CapabilityVisitor) } } @@ -113,35 +176,3 @@ impl std::fmt::Display for Capability { write!(f, "{}({})", self.issuer, self.params) } } - -/// Error type for parsing an `Address` from a string. -#[derive(Debug)] -pub enum CapabilityParseError { - MissingParenthesis, - MissingParams, - InvalidAddress, -} - -impl std::fmt::Display for CapabilityParseError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{}", - match self { - CapabilityParseError::MissingParenthesis => "Missing parenthesis around Capability", - CapabilityParseError::MissingParams => "Missing params in Capability string", - CapabilityParseError::InvalidAddress => "Invalid address in Capability string", - } - ) - } -} - -impl std::error::Error for CapabilityParseError { - fn description(&self) -> &str { - match self { - CapabilityParseError::MissingParenthesis => "Missing parenthesis around Capability", - CapabilityParseError::MissingParams => "Missing params in Capability string", - CapabilityParseError::InvalidAddress => "Invalid address in Capability string", - } - } -}