Skip to content

Commit

Permalink
Merge pull request #111 from kinode-dao/develop
Browse files Browse the repository at this point in the history
0.9.7
  • Loading branch information
nick1udwig authored Dec 3, 2024
2 parents 11daa54 + d09c01f commit dc01f89
Show file tree
Hide file tree
Showing 28 changed files with 326 additions and 192 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
16 changes: 8 additions & 8 deletions src/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand All @@ -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`.
///
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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<T: serde::de::DeserializeOwned>(
&self,
Expand Down
4 changes: 2 additions & 2 deletions src/homepage.rs
Original file line number Diff line number Diff line change
@@ -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.
///
Expand Down Expand Up @@ -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() {
Expand Down
10 changes: 5 additions & 5 deletions src/http/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<HttpClientResponse, HttpClientError>`.
/// You will receive a [`crate::Response`] with the format `Result<HttpClientResponse, HttpClientError>`.
///
/// Always serialized/deserialized as JSON.
#[derive(Clone, Debug, Serialize, Deserialize)]
Expand Down Expand Up @@ -47,7 +47,7 @@ pub struct OutgoingHttpRequest {
pub headers: HashMap<String, String>,
}

/// 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)]
Expand All @@ -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 {
Expand Down Expand Up @@ -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,
Expand Down
83 changes: 49 additions & 34 deletions src/http/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,27 @@ 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;

/// 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,
Expand All @@ -33,7 +34,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<Self> {
serde_json::from_slice(bytes)
}
Expand Down Expand Up @@ -132,9 +133,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,
Expand All @@ -144,26 +145,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
Expand All @@ -174,8 +175,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
Expand All @@ -199,26 +200,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,
Expand All @@ -230,11 +231,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<String, String>,
// BODY is stored in the lazy_load_blob, as bytes
}

impl HttpResponse {
Expand Down Expand Up @@ -268,7 +270,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}.")]
Expand All @@ -287,7 +289,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,
Expand Down Expand Up @@ -1040,11 +1042,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<String, HashSet<u32>> {
self.ws_channels.clone()
}
}

Expand Down Expand Up @@ -1078,6 +1080,19 @@ pub fn send_ws_push(channel_id: u32, message_type: WsMessageType, blob: KiBlob)
.unwrap()
}

pub fn ws_push_all_channels(
ws_channels: &HashMap<String, HashSet<u32>>,
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);
Expand Down
10 changes: 5 additions & 5 deletions src/kernel_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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<String>,
Expand All @@ -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 {
Expand Down
Loading

0 comments on commit dc01f89

Please sign in to comment.