Skip to content

Commit

Permalink
refactor: remove anyhow from everywhere but kv, sqlite, http (those n…
Browse files Browse the repository at this point in the history
…ext)
  • Loading branch information
dr-frmr committed Jul 22, 2024
1 parent fe87dd1 commit f1100a2
Show file tree
Hide file tree
Showing 9 changed files with 202 additions and 149 deletions.
62 changes: 41 additions & 21 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
//! For blobs, we recommend bincode to serialize and deserialize to bytes.
//!
pub use crate::kinode::process::standard::*;
use serde::{Deserialize, Serialize};
use serde_json::Value;

wit_bindgen::generate!({
Expand All @@ -27,28 +26,45 @@ wit_bindgen::generate!({
pub mod eth;
/// Interact with the system homepage.
///
/// Note that your process must have the capability to message
/// Your process must have the capability to message
/// `homepage:homepage:sys` to use this module.
pub mod homepage;
/// Interact with the HTTP server and client modules.
/// Contains types from the `http` crate to use as well.
///
/// Your process must have the capability to message and receive messages from
/// `http_server:distro:sys` and/or `http_client:distro:sys` to use this module.
pub mod http;
/// The types that the kernel itself uses -- warning -- these will
/// be incompatible with WIT types in some cases, leading to annoying errors.
/// Use only to interact with the kernel or runtime in certain ways.
pub mod kernel_types;
/// Interact with the kimap module
/// Interact with kimap, the onchain namespace
pub mod kimap;
/// Interact with the key_value module
///
/// Your process must have the capability to message and receive messages from
/// `kv:distro:sys` to use this module.
pub mod kv;
/// Interact with the networking module
/// For configuration, debugging, and creating signatures with networking key.
///
/// Your process must have the capability to message and receive messages from
/// `net:distro:sys` to use this module.
pub mod net;
/// Interact with the sqlite module
///
/// Your process must have the capability to message and receive messages from
/// `sqlite:distro:sys` to use this module.
pub mod sqlite;
/// Interact with the timer runtime module.
///
/// The `timer:distro:sys` module is public, so no special capabilities needed.
pub mod timer;
/// Interact with the virtual filesystem
///
/// Your process must have the capability to message and receive messages from
/// `vfs:distro:sys` to use this module.
pub mod vfs;

mod types;
Expand Down Expand Up @@ -103,7 +119,7 @@ macro_rules! println {
///
/// Example:
/// ```no_run
/// use kinode_process_lib::await_message;
/// use kinode_process_lib::{await_message, println};
///
/// loop {
/// match await_message() {
Expand All @@ -124,7 +140,8 @@ pub fn await_message() -> Result<Message, SendError> {
}
}

/// Simple wrapper over spawn() in WIT to make use of our good types
/// Spawn a new process. This function is a wrapper around the standard `spawn()` function
/// provided in `kinode::process::standard` (which is generated by the WIT file).
pub fn spawn(
name: Option<&str>,
wasm_path: &str,
Expand Down Expand Up @@ -165,9 +182,10 @@ pub fn spawn(
///
/// make_blob(&my_type, |t| Ok(bincode::serialize(t)?));
/// ```
pub fn make_blob<T, F>(blob: &T, serializer: F) -> anyhow::Result<LazyLoadBlob>
pub fn make_blob<T, F, E>(blob: &T, serializer: F) -> Result<LazyLoadBlob, E>
where
F: Fn(&T) -> anyhow::Result<Vec<u8>>,
F: Fn(&T) -> Result<Vec<u8>, E>,
E: std::error::Error,
{
Ok(LazyLoadBlob {
mime: None,
Expand Down Expand Up @@ -197,9 +215,10 @@ where
/// field_two: HashSet::new(),
/// });
/// ```
pub fn get_typed_blob<T, F>(deserializer: F) -> Option<T>
pub fn get_typed_blob<T, F, E>(deserializer: F) -> Option<T>
where
F: Fn(&[u8]) -> anyhow::Result<T>,
F: Fn(&[u8]) -> Result<T, E>,
E: std::error::Error,
{
match crate::get_blob() {
Some(blob) => match deserializer(&blob.bytes) {
Expand Down Expand Up @@ -232,9 +251,10 @@ where
/// field_two: HashSet::new(),
/// });
/// ```
pub fn get_typed_state<T, F>(deserializer: F) -> Option<T>
pub fn get_typed_state<T, F, E>(deserializer: F) -> Option<T>
where
F: Fn(&[u8]) -> anyhow::Result<T>,
F: Fn(&[u8]) -> Result<T, E>,
E: std::error::Error,
{
match crate::get_state() {
Some(bytes) => match deserializer(&bytes) {
Expand All @@ -254,21 +274,21 @@ pub fn can_message(address: &Address) -> bool {
}

/// Get a capability in our store
pub fn get_capability(our: &Address, params: &str) -> Option<Capability> {
pub fn get_capability(issuer: &Address, params: &str) -> Option<Capability> {
let params = serde_json::from_str::<Value>(params).unwrap_or_default();
crate::our_capabilities()
.iter()
.find(|cap| {
let cap_params = serde_json::from_str::<Value>(&cap.params).unwrap_or_default();
cap.issuer == *our && params == cap_params
})
.cloned()
crate::our_capabilities().into_iter().find(|cap| {
let cap_params = serde_json::from_str::<Value>(&cap.params).unwrap_or_default();
cap.issuer == *issuer && params == cap_params
})
}

/// Get the next message body from the message queue, or propagate the error
pub fn await_next_message_body() -> Result<Vec<u8>, SendError> {
match await_message() {
Ok(msg) => Ok(msg.body().to_vec()),
Err(e) => Err(e.into()),
Ok(msg) => Ok(match msg {
Message::Request { body, .. } => body,
Message::Response { body, .. } => body,
}),
Err(e) => Err(e),
}
}
30 changes: 16 additions & 14 deletions src/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,25 +175,27 @@ where
}

/// get a kimap name from namehash
pub fn get_name(
namehash: &str,
block: Option<u64>,
timeout: Option<u64>,
) -> anyhow::Result<String> {
pub fn get_name<T>(namehash: T, block: Option<u64>, timeout: Option<u64>) -> Option<String>
where
T: Into<String>,
{
let res = Request::to(("our", "kns_indexer", "kns_indexer", "sys"))
.body(
serde_json::to_vec(&IndexerRequests::NamehashToName(NamehashToNameRequest {
hash: namehash.to_string(),
block: block,
hash: namehash.into(),
block,
}))
.unwrap(),
)
.send_and_await_response(timeout.unwrap_or(5))??;
.send_and_await_response(timeout.unwrap_or(30))
.unwrap()
.ok()?;

let response = serde_json::from_slice::<IndexerResponses>(res.body());
match response {
Ok(IndexerResponses::Name(Some(name))) => Ok(name),
Ok(IndexerResponses::Name(None)) => Err(anyhow::anyhow!("name not found")),
_ => Err(anyhow::anyhow!("unexpected response: {:?}", response)),
}
let Ok(IndexerResponses::Name(maybe_name)) =
serde_json::from_slice::<IndexerResponses>(res.body())
else {
return None;
};

maybe_name
}
46 changes: 12 additions & 34 deletions src/timer.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::*;
use anyhow::Result;
use crate::{Context, Message, Request, SendError};
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum TimerAction {
Expand All @@ -10,45 +10,23 @@ pub enum TimerAction {
/// Set a timer using the runtime that will return a Response after the specified duration.
/// The duration should be a number of milliseconds.
pub fn set_timer(duration: u64, context: Option<Context>) {
match context {
None => {
Request::new()
.target(Address::new(
"our",
ProcessId::new(Some("timer"), "distro", "sys"),
))
.body(serde_json::to_vec(&TimerAction::SetTimer(duration)).unwrap())
.expects_response((duration / 1000) + 1)
// safe to unwrap this call when we know we've set both target and body
.send()
.unwrap();
}
Some(context) => {
Request::new()
.target(Address::new(
"our",
ProcessId::new(Some("timer"), "distro", "sys"),
))
.body(serde_json::to_vec(&TimerAction::SetTimer(duration)).unwrap())
.expects_response((duration / 1000) + 1)
.context(context)
// safe to unwrap this call when we know we've set both target and body
.send()
.unwrap();
}
let mut request = Request::to(("our", "timer", "distro", "sys"))
.body(serde_json::to_vec(&TimerAction::SetTimer(duration)).unwrap())
.expects_response((duration / 1000) + 1);

if let Some(context) = context {
request = request.context(context);
}
// safe to unwrap this call when we know we've set both target and body
request.send().unwrap();
}

/// Set a timer using the runtime that will return a Response after the specified duration,
/// then wait for that timer to resolve. The duration should be a number of milliseconds.
pub fn set_and_await_timer(duration: u64) -> Result<Message, SendError> {
Request::new()
.target(Address::new(
"our",
ProcessId::new(Some("timer"), "distro", "sys"),
))
Request::to(("our", "timer", "distro", "sys"))
.body(serde_json::to_vec(&TimerAction::SetTimer(duration)).unwrap())
// safe to unwrap this call when we know we've set both target and body
.send_and_await_response((duration / 1000) + 1)
// safe to unwrap this call when we know we've set both target and body
.unwrap()
}
7 changes: 4 additions & 3 deletions src/types/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,12 @@ where
}
}

impl<T> From<(&str, T)> for Address
impl<T, U> From<(T, U)> for Address
where
T: Into<ProcessId>,
T: Into<String>,
U: Into<ProcessId>,
{
fn from(input: (&str, T)) -> Self {
fn from(input: (T, U)) -> Self {
Address::new(input.0, input.1)
}
}
Expand Down
40 changes: 34 additions & 6 deletions src/types/capability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ use std::hash::{Hash, Hasher};

/// Capability is defined in the wit bindings, but constructors and methods here.
/// A `Capability` is a combination of an Address and a set of Params (a serialized
/// JSON string). Capabilities are attached to messages to either share that capability
/// with the receiving process, or to prove that a process has authority to perform a
/// certain action.
/// JSON string by convention). Capabilities are attached to messages to either share
/// that capability with the receiving process, or to prove that a process has
/// authority to perform a certain action.
impl Capability {
/// Create a new `Capability`. Takes a node ID and a process ID.
pub fn new<T, U>(address: T, params: U) -> Capability
Expand Down Expand Up @@ -172,15 +172,16 @@ impl PartialEq for Capability {

impl From<&Capability> for Capability {
fn from(input: &Capability) -> Self {
input.clone()
input.to_owned()
}
}

impl<T> From<(T, &str)> for Capability
impl<T, U> From<(T, U)> for Capability
where
T: Into<Address>,
U: Into<String>,
{
fn from(input: (T, &str)) -> Self {
fn from(input: (T, U)) -> Self {
Capability::new(input.0, input.1)
}
}
Expand All @@ -190,3 +191,30 @@ impl std::fmt::Display for Capability {
write!(f, "{}({})", self.issuer, self.params)
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::ProcessId;

#[test]
fn test_capability() {
let cap = Capability::new(
Address::new("test", ProcessId::new(None, "test", "test")),
r#"{"test": "params"}"#,
);
let serialized = serde_json::to_string(&cap).unwrap();
let deserialized: Capability = serde_json::from_str(&serialized).unwrap();
assert_eq!(cap, deserialized);
}

#[test]
fn test_capability_json() {
let cap = Capability::new(
Address::new("test", ProcessId::new(None, "test", "test")),
r#"{"test": "params"}"#,
);
let json = cap.params_json().unwrap();
assert_eq!(json, serde_json::json!({"test": "params"}));
}
}
17 changes: 17 additions & 0 deletions src/types/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,23 @@ pub enum Message {
},
}

#[derive(Debug, Serialize, Deserialize)]
pub enum BuildError {
NoBody,
NoTarget,
}

impl std::fmt::Display for BuildError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
BuildError::NoBody => write!(f, "no body set for message"),
BuildError::NoTarget => write!(f, "no target set for message"),
}
}
}

impl std::error::Error for BuildError {}

impl Message {
/// Get the source of a message.
pub fn source(&self) -> &Address {
Expand Down
Loading

0 comments on commit f1100a2

Please sign in to comment.