From 745f3ded2601912ec12de18def5d9263bb29589e Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Thu, 14 Nov 2024 13:56:23 -0800 Subject: [PATCH 01/12] bump version to 0.9.7 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e887161..2c761d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "kinode_process_lib" description = "A library for writing Kinode processes in Rust." -version = "0.9.6" +version = "0.9.7" edition = "2021" license-file = "LICENSE" homepage = "https://kinode.org" From adcd0e33f77aeec6e5dafa1eab0ee61aa5d6cb8d Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Thu, 14 Nov 2024 14:03:39 -0800 Subject: [PATCH 02/12] http: allow importing of http::StatusCode; required for use with send_response --- Cargo.lock | 2 +- src/http/server.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 224b502..f2553db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1504,7 +1504,7 @@ dependencies = [ [[package]] name = "kinode_process_lib" -version = "0.9.6" +version = "0.9.7" dependencies = [ "alloy", "alloy-primitives", diff --git a/src/http/server.rs b/src/http/server.rs index db470f8..3915f3c 100644 --- a/src/http/server.rs +++ b/src/http/server.rs @@ -3,7 +3,8 @@ use crate::{ get_blob, Address, LazyLoadBlob as KiBlob, Message, Request as KiRequest, Response as KiResponse, }; -use http::{HeaderMap, HeaderName, HeaderValue, StatusCode}; +pub use http::StatusCode; +use http::{HeaderMap, HeaderName, HeaderValue}; use serde::{Deserialize, Serialize}; use std::collections::{HashMap, HashSet}; use thiserror::Error; From ee16fe0c1356fb181b3de4835bf544f20b74033e Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Thu, 14 Nov 2024 14:04:40 -0800 Subject: [PATCH 03/12] http: add workaround for ws_push_all_channels within HttpServer::handle_request --- src/http/server.rs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/http/server.rs b/src/http/server.rs index 3915f3c..e6be763 100644 --- a/src/http/server.rs +++ b/src/http/server.rs @@ -1041,11 +1041,11 @@ impl HttpServer { /// Push a WebSocket message to all channels on a given path. pub fn ws_push_all_channels(&self, path: &str, message_type: WsMessageType, blob: KiBlob) { - if let Some(channels) = self.ws_channels.get(path) { - channels.iter().for_each(|channel_id| { - send_ws_push(*channel_id, message_type, blob.clone()); - }); - } + ws_push_all_channels(self.ws_channels, path, message_type, blob); + } + + pub fn get_ws_channels(&self) -> HashMap> { + self.ws_channels.clone() } } @@ -1079,6 +1079,19 @@ pub fn send_ws_push(channel_id: u32, message_type: WsMessageType, blob: KiBlob) .unwrap() } +pub fn ws_push_all_channels( + ws_channels: HashMap>, + path: &str, + message_type: WsMessageType, + blob: KiBlob, +) { + if let Some(channels) = ws_channels.get(path) { + channels.iter().for_each(|channel_id| { + send_ws_push(*channel_id, message_type, blob.clone()); + }); + } +} + /// Guess the MIME type of a file from its extension. pub fn get_mime_type(filename: &str) -> String { let file_path = std::path::Path::new(filename); From 51369dbe907e3685a33ab051b87162903f83960c Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Thu, 14 Nov 2024 14:12:49 -0800 Subject: [PATCH 04/12] http: make ws_push_all_channels() take a reference --- src/http/server.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/http/server.rs b/src/http/server.rs index e6be763..6b441ee 100644 --- a/src/http/server.rs +++ b/src/http/server.rs @@ -1041,7 +1041,7 @@ impl HttpServer { /// Push a WebSocket message to all channels on a given path. pub fn ws_push_all_channels(&self, path: &str, message_type: WsMessageType, blob: KiBlob) { - ws_push_all_channels(self.ws_channels, path, message_type, blob); + ws_push_all_channels(&self.ws_channels, path, message_type, blob); } pub fn get_ws_channels(&self) -> HashMap> { @@ -1080,7 +1080,7 @@ pub fn send_ws_push(channel_id: u32, message_type: WsMessageType, blob: KiBlob) } pub fn ws_push_all_channels( - ws_channels: HashMap>, + ws_channels: &HashMap>, path: &str, message_type: WsMessageType, blob: KiBlob, From 72ec27d04a4d20574ff9fc1cd03bbe0be48fc4bf Mon Sep 17 00:00:00 2001 From: "nick.kino" <79381743+nick1udwig@users.noreply.github.com> Date: Thu, 14 Nov 2024 22:03:56 -0800 Subject: [PATCH 05/12] Update README.md --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b653f20..dcecfce 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,11 @@ # `kinode_process_lib` Library of functions for more ergonomic [Kinode](https://github.com/kinode-dao/kinode) Rust process development. -Documentation can be found [here](https://docs.rs/kinode_process_lib). + +[Documentation can be found here](https://docs.rs/kinode_process_lib). + +[Crate can be found here](https://crates.io/crates/kinode_process_lib). + See the [Kinode Book](https://book.kinode.org) for a guide on how to use this library to write Kinode apps in Rust. The major version of `kinode_process_lib` will always match the major version of Kinode OS. From 5f03cd8cb01c88f309a923422af963ed02f95f52 Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Mon, 18 Nov 2024 11:29:14 -0800 Subject: [PATCH 06/12] address: add `send_request()` method --- src/types/address.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/types/address.rs b/src/types/address.rs index c6d1660..2abb049 100644 --- a/src/types/address.rs +++ b/src/types/address.rs @@ -42,6 +42,11 @@ impl Address { pub fn package_id(&self) -> crate::PackageId { crate::PackageId::new(self.package(), self.publisher()) } + + /// Send a [`Request`] to `Address`. + pub fn send_request(&self) -> Request { + Request::to(self) + } } impl std::str::FromStr for Address { From d94b517708b31ac45f91217972f529a2216d55a3 Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Mon, 18 Nov 2024 15:51:58 -0800 Subject: [PATCH 07/12] add docs links --- Cargo.lock | 2 +- src/eth.rs | 16 +++++------ src/homepage.rs | 4 +-- src/http/client.rs | 10 +++---- src/http/server.rs | 57 +++++++++++++++++++------------------ src/kernel_types.rs | 10 +++---- src/kimap.rs | 8 +++--- src/kv.rs | 8 +++--- src/lib.rs | 26 ++++++++--------- src/logging.rs | 10 +++---- src/net.rs | 8 +++--- src/scripting/mod.rs | 2 +- src/sqlite.rs | 8 +++--- src/timer.rs | 8 +++--- src/types/address.rs | 6 ++-- src/types/capability.rs | 6 ++-- src/types/lazy_load_blob.rs | 6 ++++ src/types/message.rs | 37 ++++++++++++------------ src/types/on_exit.rs | 20 ++++++------- src/types/package_id.rs | 5 ---- src/types/process_id.rs | 4 --- src/types/request.rs | 50 ++++++++++++++++---------------- src/types/response.rs | 36 +++++++++++------------ src/vfs/directory.rs | 12 ++++---- src/vfs/file.rs | 4 +-- src/vfs/mod.rs | 4 +-- 26 files changed, 183 insertions(+), 184 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 224b502..f2553db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1504,7 +1504,7 @@ dependencies = [ [[package]] name = "kinode_process_lib" -version = "0.9.6" +version = "0.9.7" dependencies = [ "alloy", "alloy-primitives", diff --git a/src/eth.rs b/src/eth.rs index 3e54900..b98d0bb 100644 --- a/src/eth.rs +++ b/src/eth.rs @@ -34,7 +34,7 @@ pub enum EthAction { }, } -/// Incoming `Request` containing subscription updates or errors that processes will receive. +/// Incoming [`crate::Request`] containing subscription updates or errors that processes will receive. /// Can deserialize all incoming requests from eth:distro:sys to this type. /// /// Will be serialized and deserialized using `serde_json::to_vec` and `serde_json::from_slice`. @@ -54,7 +54,7 @@ pub struct EthSubError { pub error: String, } -/// The Response type which a process will get from requesting with an [`EthAction`] will be +/// The [`crate::Response`] type which a process will get from requesting with an [`EthAction`] will be /// of this type, serialized and deserialized using `serde_json::to_vec` /// and `serde_json::from_slice`. /// @@ -90,7 +90,7 @@ pub enum EthError { } /// The action type used for configuring eth:distro:sys. Only processes which have the "root" -/// capability from eth:distro:sys can successfully send this action. +/// [`crate::Capability`] from eth:distro:sys can successfully send this action. #[derive(Debug, Serialize, Deserialize)] pub enum EthConfigAction { /// Add a new provider to the list of providers. @@ -126,12 +126,12 @@ pub enum EthConfigAction { pub enum EthConfigResponse { Ok, /// Response from a GetProviders request. - /// Note the [`crate::kernel_types::KnsUpdate`] will only have the correct `name` field. + /// Note the [`crate::net::KnsUpdate`] will only have the correct `name` field. /// The rest of the Update is not saved in this module. Providers(SavedConfigs), /// Response from a GetAccessSettings request. AccessSettings(AccessSettings), - /// Permission denied due to missing capability + /// Permission denied due to missing [`crate::Capability`] PermissionDenied, /// Response from a GetState request State { @@ -194,11 +194,11 @@ impl Provider { request_timeout, } } - /// Sends a request based on the specified `EthAction` and parses the response. + /// Sends a request based on the specified [`EthAction`] and parses the response. /// - /// This function constructs a request targeting the Ethereum distribution system, serializes the provided `EthAction`, + /// This function constructs a request targeting the Ethereum distribution system, serializes the provided [`EthAction`], /// and sends it. It awaits a response with a specified timeout, then attempts to parse the response into the expected - /// type `T`. This method is generic and can be used for various Ethereum actions by specifying the appropriate `EthAction` + /// type `T`. This method is generic and can be used for various Ethereum actions by specifying the appropriate [`EthAction`] /// and return type `T`. pub fn send_request_and_parse_response( &self, diff --git a/src/homepage.rs b/src/homepage.rs index 770caee..c4d2879 100644 --- a/src/homepage.rs +++ b/src/homepage.rs @@ -1,7 +1,7 @@ use crate::Request; /// Add a new icon and/or widget to the Kinode homepage. Note that the process calling this -/// function must have the `homepage:homepage:sys` messaging capability. +/// function must have the `homepage:homepage:sys` messaging [`crate::Capability`]. /// /// This should be called upon process startup to ensure that the process is added to the homepage. /// @@ -30,7 +30,7 @@ pub fn add_to_homepage(label: &str, icon: Option<&str>, path: Option<&str>, widg } /// Remove the caller process from the Kinode homepage. Note that the process calling this function -/// must have the `homepage:homepage:sys` messaging capability. +/// must have the `homepage:homepage:sys` messaging [`crate::Capability`]. /// /// This usually isn't necessary as processes are not persisted on homepage between boots. pub fn remove_from_homepage() { diff --git a/src/http/client.rs b/src/http/client.rs index 3fc00a4..8812a87 100644 --- a/src/http/client.rs +++ b/src/http/client.rs @@ -6,11 +6,11 @@ use std::collections::HashMap; use std::str::FromStr; use thiserror::Error; -/// Request type sent to the `http_client:distro:sys` service in order to open a +/// [`crate::Request`] type sent to the `http_client:distro:sys` service in order to open a /// WebSocket connection, send a WebSocket message on an existing connection, or /// send an HTTP request. /// -/// You will receive a Response with the format `Result`. +/// You will receive a [`crate::Response`] with the format `Result`. /// /// Always serialized/deserialized as JSON. #[derive(Clone, Debug, Serialize, Deserialize)] @@ -47,7 +47,7 @@ pub struct OutgoingHttpRequest { pub headers: HashMap, } -/// Request that comes from an open WebSocket client connection in the +/// [`crate::Request`] that comes from an open WebSocket client connection in the /// `http_client:distro:sys` service. Be prepared to receive these after /// using a [`HttpClientAction::WebSocketOpen`] to open a connection. #[derive(Clone, Copy, Debug, Serialize, Deserialize)] @@ -61,7 +61,7 @@ pub enum HttpClientRequest { }, } -/// Response type received from the `http_client:distro:sys` service after +/// [`crate::Response`] type received from the `http_client:distro:sys` service after /// sending a successful [`HttpClientAction`] to it. #[derive(Debug, Serialize, Deserialize)] pub enum HttpClientResponse { @@ -125,7 +125,7 @@ pub fn send_request( /// Make an HTTP request using http_client and await its response. /// -/// Returns [`Response`] from the `http` crate if successful, with the body type as bytes. +/// Returns HTTP response from the `http` crate if successful, with the body type as bytes. pub fn send_request_await_response( method: Method, url: url::Url, diff --git a/src/http/server.rs b/src/http/server.rs index db470f8..4ffb8b1 100644 --- a/src/http/server.rs +++ b/src/http/server.rs @@ -8,21 +8,21 @@ use serde::{Deserialize, Serialize}; use std::collections::{HashMap, HashSet}; use thiserror::Error; -/// HTTP Request received from the `http_server:distro:sys` service as a +/// [`crate::Request`] received from the `http_server:distro:sys` service as a /// result of either an HTTP or WebSocket binding, created via [`HttpServerAction`]. #[derive(Clone, Debug, Serialize, Deserialize)] pub enum HttpServerRequest { Http(IncomingHttpRequest), /// Processes will receive this kind of request when a client connects to them. - /// If a process does not want this websocket open, they should issue a *request* + /// If a process does not want this websocket open, they should issue a [`crate::Request`] /// containing a [`HttpServerAction::WebSocketClose`] message and this channel ID. WebSocketOpen { path: String, channel_id: u32, }, - /// Processes can both SEND and RECEIVE this kind of request + /// Processes can both SEND and RECEIVE this kind of [`crate::Request`] /// (send as [`HttpServerAction::WebSocketPush`]). - /// When received, will contain the message bytes as lazy_load_blob. + /// When received, will contain the message bytes as [`crate::LazyLoadBlob`]. WebSocketPush { channel_id: u32, message_type: WsMessageType, @@ -33,7 +33,7 @@ pub enum HttpServerRequest { } impl HttpServerRequest { - /// Parse a byte slice into an HttpServerRequest. + /// Parse a byte slice into an [`HttpServerRequest`]. pub fn from_bytes(bytes: &[u8]) -> serde_json::Result { serde_json::from_slice(bytes) } @@ -132,9 +132,9 @@ impl IncomingHttpRequest { /// The possible message types for [`HttpServerRequest::WebSocketPush`]. /// Ping and Pong are limited to 125 bytes by the WebSockets protocol. -/// Text will be sent as a Text frame, with the lazy_load_blob bytes +/// Text will be sent as a Text frame, with the [`crate::LazyLoadBlob`] bytes /// being the UTF-8 encoding of the string. Binary will be sent as a -/// Binary frame containing the unmodified lazy_load_blob bytes. +/// Binary frame containing the unmodified [`crate::LazyLoadBlob`] bytes. #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] pub enum WsMessageType { Text, @@ -144,26 +144,26 @@ pub enum WsMessageType { Close, } -/// Request type sent to `http_server:distro:sys` in order to configure it. +/// [`crate::Request`] type sent to `http_server:distro:sys` in order to configure it. /// -/// If a response is expected, all actions will return a Response +/// If a [`crate::Response`] is expected, all actions will return a [`crate::Response`] /// with the shape `Result<(), HttpServerActionError>` serialized to JSON. #[derive(Clone, Debug, Serialize, Deserialize)] pub enum HttpServerAction { - /// Bind expects a lazy_load_blob if and only if `cache` is TRUE. The lazy_load_blob should - /// be the static file to serve at this path. + /// Bind expects a [`crate::LazyLoadBlob`] if and only if `cache` is TRUE. + /// The [`crate::LazyLoadBlob`] should be the static file to serve at this path. Bind { path: String, /// Set whether the HTTP request needs a valid login cookie, AKA, whether /// the user needs to be logged in to access this path. authenticated: bool, - /// Set whether requests can be fielded from anywhere, or only the loopback address. + /// Set whether [`crate::Request`]s can be fielded from anywhere, or only the loopback address. local_only: bool, - /// Set whether to bind the lazy_load_blob statically to this path. That is, take the - /// lazy_load_blob bytes and serve them as the response to any request to this path. + /// Set whether to bind the [`crate::LazyLoadBlob`] statically to this path. That is, take the + /// [`crate::LazyLoadBlob`] bytes and serve them as the response to any request to this path. cache: bool, }, - /// SecureBind expects a lazy_load_blob if and only if `cache` is TRUE. The lazy_load_blob should + /// SecureBind expects a [`crate::LazyLoadBlob`] if and only if `cache` is TRUE. The [`crate::LazyLoadBlob`] should /// be the static file to serve at this path. /// /// SecureBind is the same as Bind, except that it forces requests to be made from @@ -174,8 +174,8 @@ pub enum HttpServerAction { /// will require the user to be logged in separately to the general domain authentication. SecureBind { path: String, - /// Set whether to bind the lazy_load_blob statically to this path. That is, take the - /// lazy_load_blob bytes and serve them as the response to any request to this path. + /// Set whether to bind the [`crate::LazyLoadBlob`] statically to this path. That is, take the + /// [`crate::LazyLoadBlob`] bytes and serve them as the response to any request to this path. cache: bool, }, /// Unbind a previously-bound HTTP path @@ -199,26 +199,26 @@ pub enum HttpServerAction { }, /// Unbind a previously-bound WebSocket path WebSocketUnbind { path: String }, - /// When sent, expects a lazy_load_blob containing the WebSocket message bytes to send. + /// When sent, expects a [`crate::LazyLoadBlob`] containing the WebSocket message bytes to send. WebSocketPush { channel_id: u32, message_type: WsMessageType, }, - /// When sent, expects a `lazy_load_blob` containing the WebSocket message bytes to send. - /// Modifies the `lazy_load_blob` by placing into `WebSocketExtPushData` with id taken from - /// this `KernelMessage` and `kinode_message_type` set to `desired_reply_type`. + /// When sent, expects a [`crate::LazyLoadBlob`] containing the WebSocket message bytes to send. + /// Modifies the [`crate::LazyLoadBlob`] by placing into [`HttpServerAction::WebSocketExtPushData`]` with id taken from + /// this [`KernelMessage`]` and `kinode_message_type` set to `desired_reply_type`. WebSocketExtPushOutgoing { channel_id: u32, message_type: WsMessageType, desired_reply_type: MessageType, }, /// For communicating with the ext. - /// Kinode's http_server sends this to the ext after receiving `WebSocketExtPushOutgoing`. + /// Kinode's http_server sends this to the ext after receiving [`HttpServerAction::WebSocketExtPushOutgoing`]. /// Upon receiving reply with this type from ext, http_server parses, setting: /// * id as given, - /// * message type as given (Request or Response), - /// * body as HttpServerRequest::WebSocketPush, - /// * blob as given. + /// * message type as given ([`crate::Request`] or [`crate::Response`]), + /// * body as [`HttpServerRequest::WebSocketPush`], + /// * [`crate::LazyLoadBlob`] as given. WebSocketExtPushData { id: u64, kinode_message_type: MessageType, @@ -230,11 +230,12 @@ pub enum HttpServerAction { /// HTTP Response type that can be shared over Wasm boundary to apps. /// Respond to [`IncomingHttpRequest`] with this type. +/// +/// BODY is stored in the [`crate::LazyLoadBlob`] as bytes #[derive(Clone, Debug, Serialize, Deserialize)] pub struct HttpResponse { pub status: u16, pub headers: HashMap, - // BODY is stored in the lazy_load_blob, as bytes } impl HttpResponse { @@ -268,7 +269,7 @@ impl HttpResponse { } } -/// Part of the Response type issued by http_server +/// Part of the [`crate::Response`] type issued by http_server #[derive(Clone, Debug, Error, Serialize, Deserialize)] pub enum HttpServerError { #[error("request could not be parsed to HttpServerAction: {req}.")] @@ -287,7 +288,7 @@ pub enum HttpServerError { UnexpectedResponse, } -/// Whether the WebSocketPush is a request or a response. +/// Whether the [`HttpServerAction::WebSocketPush`] is [`crate::Request`] or [`crate::Response`]. #[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub enum MessageType { Request, diff --git a/src/kernel_types.rs b/src/kernel_types.rs index 217ed03..43bc01e 100644 --- a/src/kernel_types.rs +++ b/src/kernel_types.rs @@ -147,7 +147,7 @@ pub enum KernelCommand { /// The process that sends this command will be given messaging capabilities /// for the new process if `public` is false. /// - /// All capabilities passed into initial_capabilities must be held by the source + /// All capabilities passed into `initial_capabilities` must be held by the source /// of this message, or the kernel will discard them (silently for now). InitializeProcess { id: ProcessId, @@ -273,7 +273,7 @@ impl StateError { /// - `image`: An optional field containing a URL to an image representing the package. /// - `external_url`: An optional field containing a URL for more information about the package. For example, a link to the github repository. /// - `animation_url`: An optional field containing a URL to an animation or video representing the package. -/// - `properties`: A requried field containing important information about the package. +/// - `properties`: A required field containing important information about the package. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Erc721Metadata { pub name: Option, @@ -288,15 +288,15 @@ pub struct Erc721Metadata { /// This follows the [ERC1155](https://github.com/ethereum/ercs/blob/master/ERCS/erc-1155.md#erc-1155-metadata-uri-json-schema) metadata standard. /// /// Fields: -/// - `package_name`: The unique name of the package, used in the `PackageId`, e.g. `package_name:publisher`. -/// - `publisher`: The KNS identity of the package publisher used in the `PackageId`, e.g. `package_name:publisher` +/// - `package_name`: The unique name of the package, used in the [`crate::PackageId`], e.g. `package_name:publisher`. +/// - `publisher`: The KNS identity of the package publisher used in the [`crate::PackageId`], e.g. `package_name:publisher` /// - `current_version`: A string representing the current version of the package, e.g. `1.0.0`. /// - `mirrors`: A list of NodeIds where the package can be found, providing redundancy. /// - `code_hashes`: A map from version names to their respective SHA-256 hashes. /// - `license`: An optional field containing the license of the package. /// - `screenshots`: An optional field containing a list of URLs to screenshots of the package. /// - `wit_version`: An optional field containing the version of the WIT standard that the package adheres to. -/// - `dependencies`: An optional field containing a list of `PackageId`s: API dependencies. +/// - `dependencies`: An optional field containing a list of [`crate::PackageId`]s: API dependencies. /// - `api_includes`: An optional field containing a list of `PathBuf`s: additional files to include in the `api.zip`. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Erc721Properties { diff --git a/src/kimap.rs b/src/kimap.rs index 4a58f21..a2f96d6 100644 --- a/src/kimap.rs +++ b/src/kimap.rs @@ -246,7 +246,7 @@ pub struct Fact { } /// Errors that can occur when decoding a log from the kimap using -/// [`decode_mint_log`] or [`decode_note_log`]. +/// [`decode_mint_log()`] or [`decode_note_log()`]. #[derive(Clone, Debug, Deserialize, Serialize)] pub enum DecodeLogError { /// The log's topic is not a mint or note event. @@ -323,7 +323,7 @@ pub fn namehash(name: &str) -> String { /// Decode a mint log from the kimap into a 'resolved' format. /// -/// Uses `valid_name` to check if the name is valid. +/// Uses [`valid_name()`] to check if the name is valid. pub fn decode_mint_log(log: &crate::eth::Log) -> Result { let contract::Note::SIGNATURE_HASH = log.topics()[0] else { return Err(DecodeLogError::UnexpectedTopic(log.topics()[0])); @@ -342,7 +342,7 @@ pub fn decode_mint_log(log: &crate::eth::Log) -> Result { /// Decode a note log from the kimap into a 'resolved' format. /// -/// Uses `valid_name` to check if the name is valid. +/// Uses [`valid_name()`] to check if the name is valid. pub fn decode_note_log(log: &crate::eth::Log) -> Result { let contract::Note::SIGNATURE_HASH = log.topics()[0] else { return Err(DecodeLogError::UnexpectedTopic(log.topics()[0])); @@ -393,7 +393,7 @@ pub fn resolve_parent(log: &crate::eth::Log, timeout: Option) -> Option) -> Option { let parent_hash = log.topics()[1].to_string(); let parent_name = net::get_name(&parent_hash, log.block_number, timeout)?; diff --git a/src/kv.rs b/src/kv.rs index 9978dc7..516880c 100644 --- a/src/kv.rs +++ b/src/kv.rs @@ -3,9 +3,9 @@ use serde::{de::DeserializeOwned, Deserialize, Serialize}; use std::marker::PhantomData; use thiserror::Error; -/// Actions are sent to a specific key value database, "db" is the name, -/// "package_id" is the package. Capabilities are checked, you can access another process's -/// database if it has given you the capability. +/// Actions are sent to a specific key value database, `db` is the name, +/// `package_id` is the [`PackageId`]. Capabilities are checked, you can access another process's +/// database if it has given you the [`crate::Capability`]. #[derive(Debug, Serialize, Deserialize)] pub struct KvRequest { pub package_id: PackageId, @@ -52,7 +52,7 @@ pub enum KvError { } /// Kv helper struct for a db. -/// Opening or creating a kv will give you a Result. +/// Opening or creating a kv will give you a `Result`. /// You can call it's impl functions to interact with it. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Kv { diff --git a/src/lib.rs b/src/lib.rs index cec9056..594679f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,13 +26,13 @@ wit_bindgen::generate!({ pub mod eth; /// Interact with the system homepage. /// -/// 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 +/// 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 @@ -43,7 +43,7 @@ pub mod kernel_types; pub mod kimap; /// Interact with the key_value module /// -/// Your process must have the capability to message and receive messages from +/// Your process must have the [`Capability`] to message and receive messages from /// `kv:distro:sys` to use this module. pub mod kv; #[cfg(feature = "logging")] @@ -51,12 +51,12 @@ pub mod logging; /// 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 +/// 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 +/// 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. @@ -65,7 +65,7 @@ pub mod sqlite; pub mod timer; /// Interact with the virtual filesystem /// -/// Your process must have the capability to message and receive messages from +/// Your process must have the [`Capability`] to message and receive messages from /// `vfs:distro:sys` to use this module. pub mod vfs; @@ -102,8 +102,8 @@ macro_rules! call_init { }; } -/// Override the println! macro to print to the terminal. Uses the -/// `print_to_terminal` function from the WIT interface on maximally-verbose +/// Override the `println!` macro to print to the terminal. +/// Uses the `print_to_terminal` function from the WIT interface on maximally-verbose /// mode, i.e., this print will always show up in the terminal. To control /// the verbosity, use the `print_to_terminal` function directly. #[macro_export] @@ -133,7 +133,7 @@ macro_rules! kiprintln { /// queueing of incoming messages, and calling this function will provide the next one. /// Interwoven with incoming messages are errors from the network. If your process /// attempts to send a message to another node, that message may bounce back with -/// a `SendError`. Those should be handled here. +/// a [`SendError`]. Those should be handled here. /// /// Example: /// ```no_run @@ -256,7 +256,7 @@ where } /// Fetch the persisted state blob associated with this process. This blob is saved -/// using the [`set_state`] function. Returns `None` if this process has no saved state. +/// using the [`set_state()`] function. Returns `None` if this process has no saved state. /// If it does, attempt to deserialize it from bytes with the provided function. /// /// Example: @@ -291,15 +291,15 @@ where } } -/// See if we have the capability to message a certain process. -/// Note if you have not saved the capability, you will not be able to message the other process. +/// See if we have the [`Capability`] to message a certain process. +/// Note if you have not saved the [`Capability`], you will not be able to message the other process. pub fn can_message(address: &Address) -> bool { crate::our_capabilities() .iter() .any(|cap| cap.params == "\"messaging\"" && cap.issuer == *address) } -/// Get a capability in our store +/// Get a [`Capability`] in our store pub fn get_capability(issuer: &Address, params: &str) -> Option { let params = serde_json::from_str::(params).unwrap_or_default(); crate::our_capabilities().into_iter().find(|cap| { diff --git a/src/logging.rs b/src/logging.rs index 58944b6..feda2c1 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -107,12 +107,12 @@ impl<'a> tracing_subscriber::fmt::MakeWriter<'a> for TerminalWriterMaker { } } -/// Initialize `tracing`-based logging for the given process at the given level. +/// Initialize [`tracing`](https://docs.rs/tracing)-based logging for the given process at the given level. /// -/// To write to logs, import the re-exported `debug!`, `info!`, `warn!`, `error!` -/// macros and use as usual. Logs will be printed to terminal as appropriate depending -/// on given level. Logs will be logged into the logging file as appropriate depending -/// on the given level. +/// To write to logs, import the re-exported [`debug!()`], [`info!()`], +/// [`warn!()`], [`error!()`] macros and use as usual. +/// Logs will be printed to terminal as appropriate depending on given level. +/// Logs will be logged into the logging file as appropriate depending on the given level. /// /// The logging file lives in the node's `vfs/` directory, specifically at /// `node/vfs/package:publisher.os/log/process.log`, where `node` is your node's home diff --git a/src/net.rs b/src/net.rs index b17cdc0..c8ab253 100644 --- a/src/net.rs +++ b/src/net.rs @@ -65,9 +65,9 @@ pub enum NetAction { /// /// This cannot be sent locally. ConnectionRequest(NodeId), - /// Can only receive from trusted source: requires net root capability. + /// Can only receive from trusted source: requires net root [`crate::Capability`]. KnsUpdate(KnsUpdate), - /// Can only receive from trusted source: requires net root capability. + /// Can only receive from trusted source: requires net root [`crate::Capability`]. KnsBatchUpdate(Vec), /// Get a list of peers with whom we have an open connection. GetPeers, @@ -161,7 +161,7 @@ impl KnsUpdate { /// Note that the given message will be prepended with the source [`Address`] /// of this message. This is done in order to not allow different processes /// on the same node to sign messages for/as one another. The receiver of -/// the signed message should use [`verify`] to verify the signature, which +/// the signed message should use [`verify()`] to verify the signature, which /// takes a `from` address to match against that prepended signing [`Address`]. /// /// This function uses a 30-second timeout to reach `net:distro:sys`. If more @@ -213,7 +213,7 @@ where }) } -/// Get a [`kimap::Kimap`] entry name from its namehash. +/// Get a [`crate::kimap::Kimap`] entry name from its namehash. /// /// Default timeout is 30 seconds. Note that the responsiveness of the indexer /// will depend on the block option used. The indexer will wait until it has diff --git a/src/scripting/mod.rs b/src/scripting/mod.rs index 4b2257f..e92922a 100644 --- a/src/scripting/mod.rs +++ b/src/scripting/mod.rs @@ -5,7 +5,7 @@ /// 1. Parse the `our` string into an `Address` object. /// 2. Wait for the first message to be sent to the process. /// 3. Convert the message body into a string. -/// 4. Call the `init` function you provide with the `Address` and the message body string. +/// 4. Call the `init` function you provide with the [`crate::Address`] and the message body string. /// /// This is best used by then using `clap` to create a `Command` and parsing the body string with it. macro_rules! script { diff --git a/src/sqlite.rs b/src/sqlite.rs index b08db9d..4a88a5e 100644 --- a/src/sqlite.rs +++ b/src/sqlite.rs @@ -3,9 +3,9 @@ use serde::{Deserialize, Serialize}; use std::collections::HashMap; use thiserror::Error; -/// Actions are sent to a specific sqlite database, "db" is the name, -/// "package_id" is the package. Capabilities are checked, you can access another process's -/// database if it has given you the capability. +/// Actions are sent to a specific sqlite database, `db` is the name, +/// `package_id` is the [`PackageId`]. Capabilities are checked, you can access another process's +/// database if it has given you the [`crate::Capability`]. #[derive(Debug, Serialize, Deserialize)] pub struct SqliteRequest { pub package_id: PackageId, @@ -74,7 +74,7 @@ pub enum SqliteError { } /// Sqlite helper struct for a db. -/// Opening or creating a db will give you a Result. +/// Opening or creating a db will give you a `Result`. /// You can call it's impl functions to interact with it. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Sqlite { diff --git a/src/timer.rs b/src/timer.rs index febe861..a946800 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -1,8 +1,8 @@ use crate::{Context, Message, Request, SendError}; use serde::{Deserialize, Serialize}; -/// The body field for requests to `timer:distro:sys`, a runtime module that allows processes -/// to set timers with a duration specified in milliseconds. +/// The [`Request::body()`] field for requests to `timer:distro:sys`, a runtime module +/// that allows processes to set timers with a duration specified in milliseconds. /// /// The timer module is public, so no particular capabilities are required to use it. #[derive(Debug, Clone, Serialize, Deserialize)] @@ -17,7 +17,7 @@ impl Into> for TimerAction { } } -/// Set a timer using the runtime that will return a Response after the specified duration. +/// Set a timer using the runtime that will return a [`crate::Response`] after the specified duration. /// The duration should be a number of milliseconds. pub fn set_timer(duration: u64, context: Option) { let mut request = Request::to(("our", "timer", "distro", "sys")) @@ -31,7 +31,7 @@ pub fn set_timer(duration: u64, context: Option) { request.send().unwrap(); } -/// Set a timer using the runtime that will return a Response after the specified duration, +/// Set a timer using the runtime that will return a [`crate::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 { Request::to(("our", "timer", "distro", "sys")) diff --git a/src/types/address.rs b/src/types/address.rs index 2abb049..f16dd3e 100644 --- a/src/types/address.rs +++ b/src/types/address.rs @@ -1,10 +1,10 @@ -pub use crate::{Address, ProcessId}; +pub use crate::{Address, ProcessId, Request}; use serde::{Deserialize, Serialize}; use std::hash::{Hash, Hasher}; /// Address is defined in `kinode.wit`, but constructors and methods here. -/// An `Address` is a combination of a node ID (string) and a [`ProcessId`]. It is -/// used in the Request/Response pattern to indicate which process on a given node +/// An Address is a combination of a node ID (string) and a [`ProcessId`]. It is +/// used in the [`Request`]/[`crate::Response`] pattern to indicate which process on a given node /// in the network to direct the message to. The formatting structure for /// an Address is `node@process_name:package_name:publisher_node` impl Address { diff --git a/src/types/capability.rs b/src/types/capability.rs index 251c9f3..aefe486 100644 --- a/src/types/capability.rs +++ b/src/types/capability.rs @@ -3,13 +3,13 @@ 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. -/// A `Capability` is a combination of an Address and a set of Params (a serialized +/// `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 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 an [`Address`] and a parameter, which is a JSON string. + /// Create a new `Capability`. Takes an [`Address`] and a parameter, which is a JSON string. pub fn new(address: T, params: U) -> Capability where T: Into
, diff --git a/src/types/lazy_load_blob.rs b/src/types/lazy_load_blob.rs index f50c929..1918639 100644 --- a/src/types/lazy_load_blob.rs +++ b/src/types/lazy_load_blob.rs @@ -1,5 +1,11 @@ pub use crate::LazyLoadBlob; +/// `LazyLoadBlob` is defined in the wit bindings, but constructors and methods here. +/// A `LazyLoadBlob` is a piece of data that is only optionally loaded into a process +/// (i.e. with `get_blob()`). `LazyLoadBlob` is useful for passing large data in a chain +/// of [`crate::Request`]s or [`crate::Response`]s where intermediate processes in the +/// chain don't need to access the data. In this way, Kinode saves time and compute +/// since the `LazyLoadBlob` is not sent back and forth across the Wasm boundary needlessly. impl LazyLoadBlob { /// Create a new `LazyLoadBlob`. Takes a mime type and a byte vector. pub fn new(mime: Option, bytes: U) -> LazyLoadBlob diff --git a/src/types/message.rs b/src/types/message.rs index 8e7ccb0..5faa55c 100644 --- a/src/types/message.rs +++ b/src/types/message.rs @@ -1,12 +1,13 @@ use crate::{Address, Capability, LazyLoadBlob, ProcessId}; use serde::{Deserialize, Serialize}; -/// The basic message type. A message is either a request or a response. Best -/// practice when handling a message is to do this: -/// 1. Match on whether it's a request or a response -/// 2. Match on who the message is from (the `source`) +/// The basic `Message` type. +/// A `Message` is either a [`crate::Request`] or a [`crate::Response`]. +/// Best practices when handling a [`Message`]: +/// 1. Match on whether its a [`crate::Request`] or a [`crate::Response`] +/// 2. Match on who the message is from (the `source` [`Address`]) /// 3. Parse and interpret the `body`, `metadata`, and/or `context` based on -/// who the message is from and what your process expects from them. +/// who the message is from and what your process expects from them. #[derive(Debug, Clone, Serialize, Deserialize)] pub enum Message { Request { @@ -43,61 +44,61 @@ impl std::fmt::Display for BuildError { impl std::error::Error for BuildError {} impl Message { - /// Get the source of a message. + /// Get the `source` [`Address`] of a `Message`. pub fn source(&self) -> &Address { match self { Message::Request { source, .. } => source, Message::Response { source, .. } => source, } } - /// Get the IPC body of a message. + /// Get the IPC body of a `Message`. pub fn body(&self) -> &[u8] { match self { Message::Request { body, .. } => body, Message::Response { body, .. } => body, } } - /// Get the metadata of a message. + /// Get the metadata of a `Message`. pub fn metadata(&self) -> Option<&str> { match self { Message::Request { metadata, .. } => metadata.as_ref().map(|s| s.as_str()), Message::Response { metadata, .. } => metadata.as_ref().map(|s| s.as_str()), } } - /// Get the context of a message. Always `None` for requests. + /// Get the context of a `Message`. Always `None` for requests. pub fn context(&self) -> Option<&[u8]> { match self { Message::Request { .. } => None, Message::Response { context, .. } => context.as_ref().map(|s| s.as_slice()), } } - /// Get the blob of a message, if any. This function must be called - /// by the process that received the message **before** receiving another - /// message! The blob can only be consumed immediately after receiving a message. + /// Get the [`LazyLoadBlob`] of a `Message`, if any. This function must be called + /// by the process that received the `Message` **before** receiving another `Message`! + /// The [`LazyLoadBlob`] can only be consumed immediately after receiving a [`Message`]. pub fn blob(&self) -> Option { crate::get_blob() } - /// Get the capabilities of a message. + /// Get the capabilities of a `Message`. pub fn capabilities(&self) -> &Vec { match self { Message::Request { capabilities, .. } => capabilities, Message::Response { capabilities, .. } => capabilities, } } - /// Check if a message is a request. Returns `false` if it's a response. + /// Check if a `Message` is a [`crate::Request`]. Returns `false` if it's a [`crate::Response`]. pub fn is_request(&self) -> bool { matches!(self, Message::Request { .. }) } - /// Check if a message was sent by a local process. Returns `false` if the - /// source node is not our local node. + /// Check if a `Message` was sent by a local process. + /// Returns `false` if the `source` node is not our local node. pub fn is_local(&self, our: &Address) -> bool { match self { Message::Request { source, .. } => source.node == our.node, Message::Response { source, .. } => source.node == our.node, } } - /// Check the `ProcessId` of a message source against a given `ProcessId` or - /// something that can be checked for equality against a `ProcessId`. + /// Check the [`ProcessId`] of a message source against a given [`ProcessId`] or + /// something that can be checked for equality against a [`ProcessId`]. pub fn is_process(&self, process: T) -> bool where ProcessId: PartialEq, diff --git a/src/types/on_exit.rs b/src/types/on_exit.rs index 81d02c7..d578309 100644 --- a/src/types/on_exit.rs +++ b/src/types/on_exit.rs @@ -8,7 +8,7 @@ pub enum OnExit { } impl OnExit { - /// Call the kernel to get the current set OnExit behavior + /// Call the kernel to get the current set `OnExit` behavior. pub fn get() -> Self { match crate::kinode::process::standard::get_on_exit() { crate::kinode::process::standard::OnExit::None => OnExit::None, @@ -31,7 +31,7 @@ impl OnExit { } } } - /// Check if this OnExit is None + /// Check if this `OnExit` is [`OnExit::None`]. pub fn is_none(&self) -> bool { match self { OnExit::None => true, @@ -39,7 +39,7 @@ impl OnExit { OnExit::Requests(_) => false, } } - /// Check if this OnExit is Restart + /// Check if this `OnExit` is [`OnExit::Restart`]. pub fn is_restart(&self) -> bool { match self { OnExit::None => false, @@ -47,7 +47,7 @@ impl OnExit { OnExit::Requests(_) => false, } } - /// Check if this OnExit is Requests + /// Check if this `OnExit` is [`OnExit::Requests`]. pub fn is_requests(&self) -> bool { match self { OnExit::None => false, @@ -55,7 +55,7 @@ impl OnExit { OnExit::Requests(_) => true, } } - /// Get the Requests variant of this OnExit, if it is one + /// Get the [`OnExit::Requests`] variant of this `OnExit`, if it is one. pub fn get_requests(&self) -> Option<&[Request]> { match self { OnExit::None => None, @@ -63,23 +63,23 @@ impl OnExit { OnExit::Requests(reqs) => Some(reqs), } } - /// Add a request to this OnExit if it is of variant `Requests` + /// Add a [`Request`] to this `OnExit` if it is of variant [`OnExit::Requests`]. pub fn add_request(&mut self, new: Request) { if let OnExit::Requests(ref mut reqs) = self { reqs.push(new); } } - /// Set the OnExit behavior for this process. + /// Set the `OnExit` behavior for this process. /// - /// Will return a [`BuildError`] if any requests within the `Requests` behavior are + /// Will return a [`BuildError`] if any requests within the [`OnExit::Requests`] behavior are /// not valid (by not having a `body` and/or `target` set). pub fn set(self) -> Result<(), BuildError> { crate::kinode::process::standard::set_on_exit(&self._to_standard()?); Ok(()) } - /// Convert this OnExit to the kernel's OnExit type. + /// Convert this `OnExit` to the kernel's `OnExit` type. /// - /// Will return a [`BuildError`] if any requests within the `Requests` behavior are + /// Will return a [`BuildError`] if any requests within the [`OnExit::Requests`] behavior are /// not valid (by not having a `body` and/or `target` set). pub fn _to_standard(self) -> Result { match self { diff --git a/src/types/package_id.rs b/src/types/package_id.rs index b65f2c5..ba0f910 100644 --- a/src/types/package_id.rs +++ b/src/types/package_id.rs @@ -132,11 +132,6 @@ impl std::str::FromStr for PackageId { /// Attempt to parse a `PackageId` from a string. The string must /// contain exactly two segments, where segments are non-empty strings /// separated by a colon (`:`). The segments cannot themselves contain colons. - /// - /// Please note that while any string without colons will parse successfully - /// to create a `PackageId`, not all strings without colons are actually - /// valid usernames, which the `publisher_node` field of a `PackageId` will - /// always in practice be. fn from_str(input: &str) -> Result { let segments: Vec<&str> = input.split(':').collect(); if segments.len() < 2 { diff --git a/src/types/process_id.rs b/src/types/process_id.rs index 608c867..8d5c83a 100644 --- a/src/types/process_id.rs +++ b/src/types/process_id.rs @@ -38,10 +38,6 @@ impl std::str::FromStr for ProcessId { type Err = ProcessIdParseError; /// Attempts to parse a `ProcessId` from a string. To succeed, the string must contain /// exactly 3 segments, separated by colons `:`. The segments must not contain colons. - /// Please note that while any string without colons will parse successfully - /// to create a `ProcessId`, not all strings without colons are actually - /// valid usernames, which the `publisher_node` field of a `ProcessId` will - /// always in practice be. fn from_str(input: &str) -> Result { let segments: Vec<&str> = input.split(':').collect(); if segments.len() < 3 { diff --git a/src/types/request.rs b/src/types/request.rs index ba4da60..aafd242 100644 --- a/src/types/request.rs +++ b/src/types/request.rs @@ -3,7 +3,7 @@ use crate::{ _wit_send_error_to_send_error, types::message::BuildError, }; -/// Request builder. Use [`Request::new()`] or [`Request::to()`] to start a request, +/// `Request` builder. Use [`Request::new()`] or [`Request::to()`] to start a request, /// then build it, then call [`Request::send()`] on it to fire. #[derive(Clone, Debug)] pub struct Request { @@ -34,9 +34,9 @@ impl Request { capabilities: vec![], } } - /// Start building a new Request with the Address of the target. In order + /// Start building a new Request with the `target` [`Address`]. In order /// to successfully send, you must still fill out at least the `body` field - /// by calling `body()` or `try_body()` next. + /// by calling [`Request::body()`] or [`Request::try_body()`] next. pub fn to(target: T) -> Self where T: Into
, @@ -64,7 +64,7 @@ impl Request { /// of the request that this process most recently received. The purpose /// of inheritance, in this setting, is twofold: /// - /// One, setting inherit to `true` and not attaching a `LazyLoadBlob` will result + /// One, setting inherit to `true` and not attaching a [`LazyLoadBlob`] will result /// in the previous request's blob being attached to this request. This /// is useful for optimizing performance of middleware and other chains of /// requests that can pass large quantities of data through multiple @@ -83,10 +83,10 @@ impl Request { self.inherit = inherit; self } - /// Set whether this request expects a response, and provide a timeout value - /// (in seconds) within which that response must be received. The sender will - /// receive an error message with this request stored within it if the - /// timeout is triggered. + /// Set whether this [`crate::Request`] expects a [`crate::Response`], and provide + /// a timeout value (in seconds) within which that response must be received. + /// The sender will receive an error message with this request stored within + /// it if the timeout is triggered. pub fn expects_response(mut self, timeout: u64) -> Self { self.timeout = Some(timeout); self @@ -98,7 +98,7 @@ impl Request { /// a JSON spec that gets stored in bytes as a UTF-8 string. /// /// If the serialization strategy is complex, it's best to define it as an impl - /// of [`TryInto`] on your IPC body type, then use `try_body()` instead of this. + /// of [`TryInto`] on your IPC body type, then use [`Request::try_body()`] instead of this. pub fn body(mut self, body: T) -> Self where T: Into>, @@ -108,8 +108,8 @@ impl Request { } /// Set the IPC body (Inter-Process Communication) value for this message, using a /// type that's got an implementation of [`TryInto`] for `Vec`. It's best - /// to define an IPC body type within your app, then implement TryFrom/TryInto for - /// all IPC body serialization/deserialization. + /// to define an IPC body type within your app, then implement [`TryFrom`]/[`TryInto`] + /// for all IPC body serialization/deserialization. pub fn try_body(mut self, body: T) -> Result where T: TryInto, Error = E>, @@ -120,7 +120,7 @@ impl Request { } /// Set the metadata field for this request. Metadata is simply a [`String`]. /// Metadata should usually be used for middleware and other message-passing - /// situations that require the original IPC body and blob to be preserved. + /// situations that require the original IPC body and [`LazyLoadBlob`] to be preserved. /// As such, metadata should not always be expected to reach the final destination /// of this request unless the full chain of behavior is known / controlled by /// the developer. @@ -132,11 +132,11 @@ impl Request { /// MIME type. /// /// The purpose of having a blob field distinct from the IPC body field is to enable - /// performance optimizations in all sorts of situations. LazyLoadBlobs are only brought + /// performance optimizations in all sorts of situations. [`LazyLoadBlob`]s are only brought /// across the runtime<>Wasm boundary if the process calls `get_blob()`, and this /// saves lots of work in data-intensive pipelines. /// - /// LazyLoadBlobs also provide a place for less-structured data, such that an IPC body type + /// [`LazyLoadBlob`]s also provide a place for less-structured data, such that an IPC body type /// can be quickly locked in and upgraded within an app-protocol without breaking /// changes, while still allowing freedom to adjust the contents and shape of a /// blob. IPC body formats should be rigorously defined. @@ -144,7 +144,7 @@ impl Request { self.blob = Some(blob); self } - /// Set the blob's MIME type. If a blob has not been set, it will be set here + /// Set the [`LazyLoadBlob`]s MIME type. If a blob has not been set, it will be set here /// as an empty vector of bytes. If it has been set, the MIME type will be replaced /// or created. pub fn blob_mime(mut self, mime: &str) -> Self { @@ -162,7 +162,7 @@ impl Request { self } } - /// Set the blob's bytes. If a blob has not been set, it will be set here with + /// Set the [`LazyLoadBlob`]s bytes. If a blob has not been set, it will be set here with /// no MIME type. If it has been set, the bytes will be replaced with these bytes. pub fn blob_bytes(mut self, bytes: T) -> Self where @@ -182,7 +182,7 @@ impl Request { self } } - /// Set the blob's bytes with a type that implements `TryInto>` + /// Set the [`LazyLoadBlob`]s bytes with a type that implements `TryInto>` /// and may or may not successfully be set. pub fn try_blob_bytes(mut self, bytes: T) -> Result where @@ -203,14 +203,14 @@ impl Request { Ok(self) } } - /// Set the context field of the request. A request's context is just another byte + /// Set the context field of the `Request`. A `Request`s context is just another byte /// vector. The developer should create a strategy for serializing and deserializing /// contexts. /// /// Contexts are useful when avoiding "callback hell". When a request is sent, any /// response or error (timeout, offline node) will be returned with this context. - /// This allows you to chain multiple asynchronous requests with their responses - /// without using complex logic to store information about outstanding requests. + /// This allows you to chain multiple asynchronous requests with their [`crate::Response`]s + /// without using complex logic to store information about outstanding `Request`s. pub fn context(mut self, context: T) -> Self where T: Into>, @@ -220,7 +220,7 @@ impl Request { } /// Attempt to set the context field of the request with a type that implements /// `TryInto>`. It's best to define a context type within your app, - /// then implement TryFrom/TryInto for all context serialization/deserialization. + /// then implement [`TryFrom`]/[`TryInto`] for all context serialization/deserialization. pub fn try_context(mut self, context: T) -> Result where T: TryInto, Error = E>, @@ -229,19 +229,19 @@ impl Request { self.context = Some(context.try_into()?); Ok(self) } - /// Attach capabilities to the next request + /// Attach capabilities to the next `Request`. pub fn capabilities(mut self, capabilities: Vec) -> Self { self.capabilities = capabilities; self } - /// Attach the capability to message this process to the next message. + /// Attach the [`Capability`] to message this process to the next message. pub fn attach_messaging(mut self, our: &Address) { self.capabilities.extend(vec![Capability { issuer: our.clone(), params: "\"messaging\"".to_string(), }]); } - /// Attempt to send the request. This will only fail if the `target` or `body` + /// Attempt to send the `Request`. This will only fail if the `target` or `body` /// fields have not been set. pub fn send(self) -> Result<(), BuildError> { let Some(target) = self.target else { @@ -264,7 +264,7 @@ impl Request { ); Ok(()) } - /// Attempt to send the request, then await its response or error (timeout, offline node). + /// Attempt to send the `Request`, then await its [`crate::Response`] or [`SendError`] (timeout, offline node). /// This will only fail if the `target` or `body` fields have not been set. pub fn send_and_await_response( self, diff --git a/src/types/response.rs b/src/types/response.rs index a8d8f81..9554e98 100644 --- a/src/types/response.rs +++ b/src/types/response.rs @@ -1,6 +1,6 @@ use crate::{types::message::BuildError, Capability, LazyLoadBlob}; -/// Response builder. Use [`Response::new()`] to start a response, then build it, +/// `Response` builder. Use [`Response::new()`] to start a `Response`, then build it, /// then call [`Response::send()`] on it to fire. pub struct Response { inherit: bool, @@ -11,8 +11,8 @@ pub struct Response { } impl Response { - /// Start building a new response. Attempting to send this response will - /// not succeed until its `body` has been set with `body()` or `try_body()`. + /// Start building a new `Response`. Attempting to send this `Response` will not succeed + /// until its `body` has been set with [`Response::body()` or [`Response::try_body()`]. pub fn new() -> Self { Response { inherit: false, @@ -22,12 +22,12 @@ impl Response { capabilities: vec![], } } - /// Set whether this response will "inherit" the blob of the request - /// that this process most recently received. Unlike with requests, the - /// inherit field of a response only deals with blob attachment, since - /// responses don't themselves have to consider responses or contexts. + /// Set whether this `Response` will "inherit" the blob of the [`crate::Request`] + /// that this process most recently received. Unlike with [`crate::Request`]s, the + /// inherit field of a `Response` only deals with blob attachment, since + /// `Response`s don't themselves have to consider `Response`s or contexts. /// - /// *Note that if the blob is set for this response, this flag will not + /// *Note that if the blob is set for this `Response`, this flag will not /// override it.* pub fn inherit(mut self, inherit: bool) -> Self { self.inherit = inherit; @@ -40,7 +40,7 @@ impl Response { /// a JSON spec that gets stored in bytes as a UTF-8 string. /// /// If the serialization strategy is complex, it's best to define it as an impl - /// of [`TryInto`] on your IPC body type, then use `try_body()` instead of this. + /// of [`TryInto`] on your IPC body type, then use [`Response::try_body()`] instead of this. pub fn body(mut self, body: T) -> Self where T: Into>, @@ -50,7 +50,7 @@ impl Response { } /// Set the IPC body (Inter-Process Communication) value for this message, using a /// type that's got an implementation of [`TryInto`] for `Vec`. It's best - /// to define an IPC body type within your app, then implement TryFrom/TryInto for + /// to define an IPC body type within your app, then implement [`TryFrom`]/[`TryInto`] for /// all IPC body serialization/deserialization. pub fn try_body(mut self, body: T) -> Result where @@ -74,11 +74,11 @@ impl Response { /// MIME type. /// /// The purpose of having a blob field distinct from the IPC body field is to enable - /// performance optimizations in all sorts of situations. LazyLoadBlobs are only brought + /// performance optimizations in all sorts of situations. [`LazyLoadBlob`]s are only brought /// across the runtime<>Wasm boundary if the process calls `get_blob()`, and this /// saves lots of work in data-intensive pipelines. /// - /// LazyLoadBlobs also provide a place for less-structured data, such that an IPC body type + /// [`LazyLoadBlob`]s also provide a place for less-structured data, such that an IPC body type /// can be quickly locked in and upgraded within an app-protocol without breaking /// changes, while still allowing freedom to adjust the contents and shape of a /// blob. IPC body formats should be rigorously defined. @@ -86,7 +86,7 @@ impl Response { self.blob = Some(blob); self } - /// Set the blob's MIME type. If a blob has not been set, it will be set here + /// Set the [`LazyLoadBlob`]s MIME type. If a blob has not been set, it will be set here /// as an empty vector of bytes. If it has been set, the MIME type will be replaced /// or created. pub fn blob_mime(mut self, mime: &str) -> Self { @@ -104,7 +104,7 @@ impl Response { self } } - /// Set the blob's bytes. If a blob has not been set, it will be set here with + /// Set the [`LazyLoadBlob`]s bytes. If a blob has not been set, it will be set here with /// no MIME type. If it has been set, the bytes will be replaced with these bytes. pub fn blob_bytes(mut self, bytes: T) -> Self where @@ -124,7 +124,7 @@ impl Response { self } } - /// Set the blob's bytes with a type that implements `TryInto>` + /// Set the [`LazyLoadBlob`]s bytes with a type that implements `TryInto>` /// and may or may not successfully be set. pub fn try_blob_bytes(mut self, bytes: T) -> Result where @@ -145,13 +145,13 @@ impl Response { Ok(self) } } - /// Add capabilities to this response. Capabilities are a way to pass + /// Attach capabilities to this next `Response`. pub fn capabilities(mut self, capabilities: Vec) -> Self { self.capabilities = capabilities; self } - /// Attempt to send the response. This will only fail if the IPC body field of - /// the response has not yet been set using `body()` or `try_body()`. + /// Attempt to send the `Response`. This will only fail if the IPC body field of + /// the `Response` has not yet been set using `body()` or `try_body()`. pub fn send(self) -> Result<(), BuildError> { if let Some(body) = self.body { crate::send_response( diff --git a/src/vfs/directory.rs b/src/vfs/directory.rs index 2fc07cf..2069876 100644 --- a/src/vfs/directory.rs +++ b/src/vfs/directory.rs @@ -1,7 +1,7 @@ use super::{parse_response, vfs_request, DirEntry, FileType, VfsAction, VfsError, VfsResponse}; -/// Vfs helper struct for a directory. -/// Opening or creating a directory will give you a Result. +/// VFS (Virtual File System) helper struct for a directory. +/// Opening or creating a directory will give you a `Result`. /// You can call it's impl functions to interact with it. pub struct Directory { pub path: String, @@ -9,7 +9,7 @@ pub struct Directory { } impl Directory { - /// Iterates through children of directory, returning a vector of DirEntries. + /// Iterates through children of `Directory`, returning a vector of DirEntries. /// DirEntries contain the path and file type of each child. pub fn read(&self) -> Result, VfsError> { let message = vfs_request(&self.path, VfsAction::ReadDir) @@ -31,8 +31,8 @@ impl Directory { } } -/// Opens or creates a directory at path. -/// If trying to create an existing directory, will just give you the path. +/// Opens or creates a `Directory` at path. +/// If trying to create an existing `Directory`, will just give you the path. pub fn open_dir(path: &str, create: bool, timeout: Option) -> Result { let timeout = timeout.unwrap_or(5); if !create { @@ -88,7 +88,7 @@ pub fn open_dir(path: &str, create: bool, timeout: Option) -> Result) -> Result<(), VfsError> { let timeout = timeout.unwrap_or(5); diff --git a/src/vfs/file.rs b/src/vfs/file.rs index f4718ff..e73c071 100644 --- a/src/vfs/file.rs +++ b/src/vfs/file.rs @@ -3,8 +3,8 @@ use super::{ }; use crate::{get_blob, PackageId}; -/// Vfs helper struct for a file. -/// Opening or creating a file will give you a `Result`. +/// VFS (Virtual File System) helper struct for a file. +/// Opening or creating a `File` will give you a `Result`. /// You can call its impl functions to interact with it. pub struct File { pub path: String, diff --git a/src/vfs/mod.rs b/src/vfs/mod.rs index 3f705b1..6fdd5b7 100644 --- a/src/vfs/mod.rs +++ b/src/vfs/mod.rs @@ -8,10 +8,10 @@ pub mod file; pub use directory::*; pub use file::*; -/// IPC body format for requests sent to vfs runtime module +/// IPC body format for requests sent to vfs runtime module. #[derive(Debug, Serialize, Deserialize)] pub struct VfsRequest { - /// path is always prepended by package_id, the capabilities of the topmost folder are checked + /// path is always prepended by [`crate::PackageId`], the capabilities of the topmost folder are checked /// "/your_package:publisher.os/drive_folder/another_folder_or_file" pub path: String, pub action: VfsAction, From 36d7220733e74375e3efc079ffd598aeed2dae36 Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Wed, 20 Nov 2024 10:52:44 -0800 Subject: [PATCH 08/12] add `Spawn!()` noop macro --- src/lib.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 594679f..9534001 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -307,3 +307,31 @@ pub fn get_capability(issuer: &Address, params: &str) -> Option { cap.issuer == *issuer && params == cap_params }) } + +/// The `Spawn!()` macro is defined here as a no-op. +/// However, in practice, `kit build` will rewrite it during pre-processing. +/// +/// Example: +/// ```no_run +/// fn init(our: Address) { +/// Spawn!(|our| { +/// println!("hello from {our}. I am Spawn of {}!", args["our"]); +/// }); +/// ... +/// } +/// ``` +/// will be rewritten by `kit build` to: +/// 1. Generate a new child process within the package that, here, `println!()`s, +/// or, in general, executes the code given by the closure. +/// 2. Replace the code lines in the parent process with [`spawn()`] to start +/// the generated child and send a [`Request()`] to pass in the closure's args. +/// 3. Update the relevant metadata for the package +/// (i.e. `Cargo.toml`, `metadata.json`, etc.). +#[macro_export] +macro_rules! Spawn { + // Matches a closure with one parameter + (|$param:ident| $body:block) => {}; + + // If you also need to support multiple parameters in the closure: + (|$($param:ident),*| $body:block) => {}; +} From a690b4d49aae078b191885b6933f2fb050bbb705 Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Wed, 20 Nov 2024 16:59:56 -0800 Subject: [PATCH 09/12] change `Spawn!()` to require arg types --- src/lib.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 9534001..85fc96e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -314,7 +314,8 @@ pub fn get_capability(issuer: &Address, params: &str) -> Option { /// Example: /// ```no_run /// fn init(our: Address) { -/// Spawn!(|our| { +/// let parent = our.clone(); +/// Spawn!(|parent: Address| { /// println!("hello from {our}. I am Spawn of {}!", args["our"]); /// }); /// ... @@ -329,9 +330,6 @@ pub fn get_capability(issuer: &Address, params: &str) -> Option { /// (i.e. `Cargo.toml`, `metadata.json`, etc.). #[macro_export] macro_rules! Spawn { - // Matches a closure with one parameter - (|$param:ident| $body:block) => {}; - - // If you also need to support multiple parameters in the closure: - (|$($param:ident),*| $body:block) => {}; + // Match one or more type-annotated parameters + (|$($param:ident : $type:ty),+ $(,)?| $body:block) => {}; } From e8cf052d797816b535b43ffccdc6e4c903387a04 Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Thu, 21 Nov 2024 21:16:56 -0800 Subject: [PATCH 10/12] allow `Spawn!()` to accept a function as argument --- src/lib.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 85fc96e..14f82ca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -311,7 +311,7 @@ pub fn get_capability(issuer: &Address, params: &str) -> Option { /// The `Spawn!()` macro is defined here as a no-op. /// However, in practice, `kit build` will rewrite it during pre-processing. /// -/// Example: +/// Examples: /// ```no_run /// fn init(our: Address) { /// let parent = our.clone(); @@ -328,8 +328,20 @@ pub fn get_capability(issuer: &Address, params: &str) -> Option { /// the generated child and send a [`Request()`] to pass in the closure's args. /// 3. Update the relevant metadata for the package /// (i.e. `Cargo.toml`, `metadata.json`, etc.). +/// +/// +/// ```no_run +/// fn init(our: Address) { +/// let parent = our.clone(); +/// Spawn!(my_function(parent)); +/// ... +/// } +/// ``` #[macro_export] macro_rules! Spawn { - // Match one or more type-annotated parameters + // Pattern 1: Match closure with type-annotated parameters (|$($param:ident : $type:ty),+ $(,)?| $body:block) => {}; + + // Pattern 2: Match function call + ($fn_name:ident($($arg:expr),* $(,)?)) => {}; } From 2c9813634fcde3451f413d295861c400ddbf86b2 Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Fri, 22 Nov 2024 08:58:48 -0800 Subject: [PATCH 11/12] allow optional paramters to Spawn!()` --- src/lib.rs | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 14f82ca..cd4027c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -316,7 +316,7 @@ pub fn get_capability(issuer: &Address, params: &str) -> Option { /// fn init(our: Address) { /// let parent = our.clone(); /// Spawn!(|parent: Address| { -/// println!("hello from {our}. I am Spawn of {}!", args["our"]); +/// println!("hello from {our}. I am Spawn of {parent}!"); /// }); /// ... /// } @@ -329,7 +329,9 @@ pub fn get_capability(issuer: &Address, params: &str) -> Option { /// 3. Update the relevant metadata for the package /// (i.e. `Cargo.toml`, `metadata.json`, etc.). /// +/// More example usage: /// +/// Can pass function call rather than closure: /// ```no_run /// fn init(our: Address) { /// let parent = our.clone(); @@ -337,11 +339,83 @@ pub fn get_capability(issuer: &Address, params: &str) -> Option { /// ... /// } /// ``` +/// Nested function calls work as expected. +/// +/// Can optionally supply subset of [`spawn()`] arguments, namely +/// * name: &str, +/// * on_exit: [`OnExit`], +/// * request_capabilities: Vec<[`Capability`]>, +/// * grant_capabilities: Vec<[`ProcessId`]>, +/// * public: bool, +/// for example: +/// ```no_run +/// fn init(our: Address) { +/// let parent = our.clone(); +/// Spawn!(my_function(parent), name: "hello-world", public: true); +/// ... +/// } +/// ``` #[macro_export] macro_rules! Spawn { - // Pattern 1: Match closure with type-annotated parameters + // Pattern 1: Closure with type-annotated paramters & with no options (|$($param:ident : $type:ty),+ $(,)?| $body:block) => {}; - // Pattern 2: Match function call + // Pattern 2: Function call with no options ($fn_name:ident($($arg:expr),* $(,)?)) => {}; + + // Pattern 3: Closure with type-annotated paramters & with options + ( + |$($param:ident : $type:ty),+ $(,)?| $body:block, + $( + $key:ident : $value:expr + $(,)? + )* + ) => {{ + // Validate each key at compile time using nested macro + validate_spawn_args!($($key),*); + + // Your implementation here + }}; + + // Pattern 4: Function call with options + ( + $fn_name:ident($($arg:expr),* $(,)?), + $( + $key:ident : $value:expr + $(,)? + )* + ) => {{ + // Validate each key at compile time using nested macro + validate_spawn_args!($($key),*); + + // Your implementation here + }}; +} + +#[macro_export] +macro_rules! validate_spawn_args { + // Empty case - no args to validate + () => {}; + + // Validate single argument + (name) => {}; + (on_exit) => {}; + (request_capabilities) => {}; + (grant_capabilities) => {}; + (public) => {}; + + // Recursively validate multiple arguments + ($first:ident, $($rest:ident),+ $(,)?) => { + validate_spawn_args!($first); + validate_spawn_args!($($rest),+); + }; + + // Error case - invalid argument name + ($invalid:ident $(, $($rest:tt)*)?) => { + compile_error!(concat!( + "Invalid Spawn argument '", + stringify!($invalid), + "'. Valid options are: name, on_exit, request_capabilities, grant_capabilities, public" + )); + }; } From 09cd590943ff5e071b30cf7c13f8e18cbf317e1a Mon Sep 17 00:00:00 2001 From: hosted-fornet Date: Fri, 22 Nov 2024 16:19:25 -0800 Subject: [PATCH 12/12] fix `Spawn!()` helper macro --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index cd4027c..0bc679a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -372,7 +372,7 @@ macro_rules! Spawn { )* ) => {{ // Validate each key at compile time using nested macro - validate_spawn_args!($($key),*); + $crate::validate_spawn_args!($($key),*); // Your implementation here }}; @@ -386,7 +386,7 @@ macro_rules! Spawn { )* ) => {{ // Validate each key at compile time using nested macro - validate_spawn_args!($($key),*); + $crate::validate_spawn_args!($($key),*); // Your implementation here }};