From d880b8d2c91c2b078556ff95180e4b5811dc85f4 Mon Sep 17 00:00:00 2001 From: z Date: Tue, 15 Jul 2025 15:11:13 +1200 Subject: [PATCH 1/5] added CI to test all features dynamically --- .github/workflows/ci.yaml | 47 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index de5bf8a..509c4f1 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -24,3 +24,50 @@ jobs: run: cargo check --release --all --all-features - name: Test run: cargo test --all --features mock-ffi + + get-features: + runs-on: ubuntu-latest + outputs: + features: ${{ steps.get-features.outputs.features }} + steps: + - name: Check out + uses: actions/checkout@v4 + - name: Install toml-cli + run: cargo install toml-cli + - name: Extract features from Cargo.toml + id: get-features + run: | + # Extract all feature names from Cargo.toml + all_features=$(toml get Cargo.toml features | jq -r 'keys[]') + + # Filter out default, serde, and mock-ffi + features=$(echo "$all_features" | grep -v -E '^(default|serde|mock-ffi)$' | jq -R -s -c 'split("\n") | map(select(length > 0))') + + # Add "default" and "all" to test with default features and all features + features=$(echo $features | jq -c '. + ["default", "all"]') + + echo "features=$features" >> $GITHUB_OUTPUT + echo "Detected features: $features" + + feature-matrix: + needs: get-features + runs-on: ubuntu-latest + strategy: + matrix: + feature: ${{ fromJson(needs.get-features.outputs.features) }} + steps: + - name: Check out + uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@1.85.0 + with: + toolchain: stable + targets: wasm32-wasip1 + - name: Check feature ${{ matrix.feature }} + run: | + if [ "${{ matrix.feature }}" = "default" ]; then + cargo check --release + elif [ "${{ matrix.feature }}" = "all" ]; then + cargo check --release --all-features + else + cargo check --release --no-default-features --features ${{ matrix.feature }} + fi From 0d32b632e2cb6277214ebfbd04243516a0ba9d25 Mon Sep 17 00:00:00 2001 From: z Date: Tue, 15 Jul 2025 15:18:42 +1200 Subject: [PATCH 2/5] removed serde --- .github/workflows/ci.yaml | 4 ++-- Cargo.toml | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 509c4f1..40b6f7c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -40,8 +40,8 @@ jobs: # Extract all feature names from Cargo.toml all_features=$(toml get Cargo.toml features | jq -r 'keys[]') - # Filter out default, serde, and mock-ffi - features=$(echo "$all_features" | grep -v -E '^(default|serde|mock-ffi)$' | jq -R -s -c 'split("\n") | map(select(length > 0))') + # Filter out default and mock-ffi + features=$(echo "$all_features" | grep -v -E '^(default|mock-ffi)$' | jq -R -s -c 'split("\n") | map(select(length > 0))') # Add "default" and "all" to test with default features and all features features=$(echo $features | jq -c '. + ["default", "all"]') diff --git a/Cargo.toml b/Cargo.toml index 1d63d1a..19b9cd9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,22 @@ serde_json = { version = "1.0", default-features = false, features = ["alloc"] } url = { version = "2.5", default-features = false } [features] -default = ["serde"] +default = [ + "serde", + "http", + "llm", + "bless-crawl", + "cgi", + "socket", + "memory", + "rpc", +] serde = ["dep:serde"] mock-ffi = [] +http = ["rpc","serde"] +llm = ["serde"] +bless-crawl = ["serde", "http"] +cgi = [] +socket = [] +memory = [] +rpc = ["serde"] From 92166424ad26389a309cfceba3838541b168866a Mon Sep 17 00:00:00 2001 From: z Date: Tue, 15 Jul 2025 15:18:55 +1200 Subject: [PATCH 3/5] added feature flags for supported features --- Cargo.toml | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 19b9cd9..be9f46b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,18 +10,17 @@ license = "MIT/Apache-2.0" repository = "https://github.com/blocklessnetwork/sdk-rust" [dependencies] -base64 = { version = "0.13", default-features = false, features = ["alloc"] } -htmd = { version = "0.2.2", default-features = false } +base64 = { version = "0.13", default-features = false, features = ["alloc"], optional = true } +htmd = { version = "0.2.2", default-features = false, optional = true } json = { version = "0.12", default-features = false } -kuchikiki = { version = "0.8", default-features = false } -regex = { version = "1.11.1", default-features = false, features = ["unicode-case"] } +kuchikiki = { version = "0.8", default-features = false, optional = true } +regex = { version = "1.11.1", default-features = false, features = ["unicode-case"], optional = true } serde = { version = "1.0", features = ["derive"], optional = true } serde_json = { version = "1.0", default-features = false, features = ["alloc"] } url = { version = "2.5", default-features = false } [features] default = [ - "serde", "http", "llm", "bless-crawl", @@ -30,12 +29,11 @@ default = [ "memory", "rpc", ] -serde = ["dep:serde"] mock-ffi = [] -http = ["rpc","serde"] -llm = ["serde"] -bless-crawl = ["serde", "http"] +http = ["rpc", "dep:serde"] +llm = ["dep:serde"] +bless-crawl = ["http", "dep:base64", "dep:htmd", "dep:kuchikiki", "dep:regex", "dep:serde"] cgi = [] socket = [] memory = [] -rpc = ["serde"] +rpc = ["dep:serde"] From a5826b5cd82f8878315dd4a1153fa5df1c790ecf Mon Sep 17 00:00:00 2001 From: z Date: Tue, 15 Jul 2025 15:21:33 +1200 Subject: [PATCH 4/5] removed errors - moved to module; added feature-flags for each feature, updated examples --- examples/coingecko_oracle.rs | 5 +- examples/llm-mcp.rs | 2 +- examples/llm.rs | 2 +- examples/web-scrape.rs | 2 +- src/cgi.rs | 26 ++++++++- src/error.rs | 107 ----------------------------------- src/lib.rs | 30 +++++----- src/llm.rs | 6 +- src/socket.rs | 23 +++++++- 9 files changed, 70 insertions(+), 133 deletions(-) delete mode 100644 src/error.rs diff --git a/examples/coingecko_oracle.rs b/examples/coingecko_oracle.rs index 09338fc..3837506 100644 --- a/examples/coingecko_oracle.rs +++ b/examples/coingecko_oracle.rs @@ -1,10 +1,9 @@ use blockless_sdk::http::HttpClient; -use blockless_sdk::read_stdin; +use blockless_sdk::memory::read_stdin; use serde_json::json; use std::collections::HashMap; -#[cfg_attr(feature = "serde", derive(serde::Serialize))] -#[derive(Debug)] +#[derive(Debug, serde::Serialize)] struct CoinPrice { id: String, price: u64, diff --git a/examples/llm-mcp.rs b/examples/llm-mcp.rs index 74d56f7..fd4ab58 100644 --- a/examples/llm-mcp.rs +++ b/examples/llm-mcp.rs @@ -1,4 +1,4 @@ -use blockless_sdk::*; +use blockless_sdk::llm::*; /// This example demonstrates how to use the Blockless SDK to interact with two different LLM models /// and use MCP to call the tools. diff --git a/examples/llm.rs b/examples/llm.rs index 8be94d2..83653ba 100644 --- a/examples/llm.rs +++ b/examples/llm.rs @@ -1,4 +1,4 @@ -use blockless_sdk::*; +use blockless_sdk::llm::*; /// This example demonstrates how to use the Blockless SDK to interact with two different LLM models. /// diff --git a/examples/web-scrape.rs b/examples/web-scrape.rs index d4165a3..552aa39 100644 --- a/examples/web-scrape.rs +++ b/examples/web-scrape.rs @@ -1,4 +1,4 @@ -use blockless_sdk::*; +use blockless_sdk::bless_crawl::*; /// This example demonstrates how to use the Blockless SDK to perform web scraping /// using the BlessCrawl functionality. diff --git a/src/cgi.rs b/src/cgi.rs index c4ffc4a..e63cbb2 100644 --- a/src/cgi.rs +++ b/src/cgi.rs @@ -1,4 +1,3 @@ -use crate::CGIErrorKind; use json::{object::Object, JsonValue}; use std::fmt::{Debug, Display}; @@ -280,3 +279,28 @@ impl CGIListExtensions { Ok(externs) } } + +#[derive(Debug)] +pub enum CGIErrorKind { + ListError, + EncodingError, + JsonDecodingError, + ExecError, + ReadError, + NoCommandError, +} + +impl std::fmt::Display for CGIErrorKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + CGIErrorKind::ListError => write!(f, "CGI List Error."), + CGIErrorKind::EncodingError => write!(f, "CGI Encoding Error."), + CGIErrorKind::JsonDecodingError => write!(f, "Json decoding Error."), + CGIErrorKind::ExecError => write!(f, "CGI Exec Error."), + CGIErrorKind::ReadError => write!(f, "Read Error."), + CGIErrorKind::NoCommandError => write!(f, "No CGI Command Error."), + } + } +} + +impl std::error::Error for CGIErrorKind {} diff --git a/src/error.rs b/src/error.rs deleted file mode 100644 index c1fea7b..0000000 --- a/src/error.rs +++ /dev/null @@ -1,107 +0,0 @@ -#[derive(Debug)] -pub enum HttpErrorKind { - InvalidDriver, - InvalidHandle, - MemoryAccessError, - BufferTooSmall, - HeaderNotFound, - Utf8Error, - DestinationNotAllowed, - InvalidMethod, - InvalidEncoding, - InvalidUrl, - RequestError, - RuntimeError, - TooManySessions, - PermissionDeny, -} - -impl std::error::Error for HttpErrorKind {} - -impl std::fmt::Display for HttpErrorKind { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match *self { - Self::InvalidDriver => write!(f, "Invalid Driver"), - Self::InvalidHandle => write!(f, "Invalid Error"), - Self::MemoryAccessError => write!(f, "Memoery Access Error"), - Self::BufferTooSmall => write!(f, "Buffer too small"), - Self::HeaderNotFound => write!(f, "Header not found"), - Self::Utf8Error => write!(f, "Utf8 error"), - Self::DestinationNotAllowed => write!(f, "Destination not allowed"), - Self::InvalidMethod => write!(f, "Invalid method"), - Self::InvalidEncoding => write!(f, "Invalid encoding"), - Self::InvalidUrl => write!(f, "Invalid url"), - Self::RequestError => write!(f, "Request url"), - Self::RuntimeError => write!(f, "Runtime error"), - Self::TooManySessions => write!(f, "Too many sessions"), - Self::PermissionDeny => write!(f, "Permision deny."), - } - } -} - -impl From for HttpErrorKind { - fn from(i: u32) -> HttpErrorKind { - match i { - 1 => HttpErrorKind::InvalidHandle, - 2 => HttpErrorKind::MemoryAccessError, - 3 => HttpErrorKind::BufferTooSmall, - 4 => HttpErrorKind::HeaderNotFound, - 5 => HttpErrorKind::Utf8Error, - 6 => HttpErrorKind::DestinationNotAllowed, - 7 => HttpErrorKind::InvalidMethod, - 8 => HttpErrorKind::InvalidEncoding, - 9 => HttpErrorKind::InvalidUrl, - 10 => HttpErrorKind::RequestError, - 11 => HttpErrorKind::RuntimeError, - 12 => HttpErrorKind::TooManySessions, - 13 => HttpErrorKind::PermissionDeny, - _ => HttpErrorKind::RuntimeError, - } - } -} - -#[derive(Debug)] -pub enum SocketErrorKind { - ConnectRefused, - ParameterError, - ConnectionReset, - AddressInUse, -} - -impl std::fmt::Display for SocketErrorKind { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match *self { - SocketErrorKind::ConnectRefused => write!(f, "Connect Refused."), - SocketErrorKind::ParameterError => write!(f, "Parameter Error."), - SocketErrorKind::ConnectionReset => write!(f, "Connection Reset."), - SocketErrorKind::AddressInUse => write!(f, "Address In Use."), - } - } -} - -impl std::error::Error for SocketErrorKind {} - -#[derive(Debug)] -pub enum CGIErrorKind { - ListError, - EncodingError, - JsonDecodingError, - ExecError, - ReadError, - NoCommandError, -} - -impl std::fmt::Display for CGIErrorKind { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match *self { - CGIErrorKind::ListError => write!(f, "CGI List Error."), - CGIErrorKind::EncodingError => write!(f, "CGI Encoding Error."), - CGIErrorKind::JsonDecodingError => write!(f, "Json decoding Error."), - CGIErrorKind::ExecError => write!(f, "CGI Exec Error."), - CGIErrorKind::ReadError => write!(f, "Read Error."), - CGIErrorKind::NoCommandError => write!(f, "No CGI Command Error."), - } - } -} - -impl std::error::Error for CGIErrorKind {} diff --git a/src/lib.rs b/src/lib.rs index 7328e1b..80bfe1d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,16 +1,20 @@ -mod bless_crawl; -mod cgi; -mod error; -mod llm; -mod memory; -mod socket; +#[cfg(feature = "rpc")] +pub mod rpc; + +#[cfg(feature = "cgi")] +pub mod cgi; + +#[cfg(feature = "llm")] +pub mod llm; +#[cfg(feature = "memory")] +pub mod memory; + +#[cfg(feature = "socket")] +pub mod socket; + +#[cfg(feature = "http")] pub mod http; -pub mod rpc; -pub use bless_crawl::*; -pub use cgi::*; -pub use error::*; -pub use llm::*; -pub use memory::*; -pub use socket::*; +#[cfg(feature = "bless-crawl")] +pub mod bless_crawl; diff --git a/src/llm.rs b/src/llm.rs index 87b7421..a409417 100644 --- a/src/llm.rs +++ b/src/llm.rs @@ -184,16 +184,14 @@ impl std::fmt::Display for Models { } } -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)] pub struct BlocklessLlm { inner: Handle, model_name: String, options: LlmOptions, } -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[derive(Debug, Clone, Default, PartialEq)] +#[derive(Debug, Clone, Default, PartialEq, serde::Serialize, serde::Deserialize)] pub struct LlmOptions { pub system_message: Option, pub tools_sse_urls: Option>, diff --git a/src/socket.rs b/src/socket.rs index 6a31e0e..9cf4bc4 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -1,5 +1,3 @@ -use crate::SocketErrorKind; - #[cfg(not(feature = "mock-ffi"))] #[link(wasm_import_module = "blockless_socket")] extern "C" { @@ -42,3 +40,24 @@ pub fn create_tcp_bind_socket(addr: &str) -> Result { }) } } + +#[derive(Debug)] +pub enum SocketErrorKind { + ConnectRefused, + ParameterError, + ConnectionReset, + AddressInUse, +} + +impl std::fmt::Display for SocketErrorKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + SocketErrorKind::ConnectRefused => write!(f, "Connect Refused."), + SocketErrorKind::ParameterError => write!(f, "Parameter Error."), + SocketErrorKind::ConnectionReset => write!(f, "Connection Reset."), + SocketErrorKind::AddressInUse => write!(f, "Address In Use."), + } + } +} + +impl std::error::Error for SocketErrorKind {} From 4b656a88150ef456aa6f711eae8ce8fc119a6471 Mon Sep 17 00:00:00 2001 From: z Date: Tue, 15 Jul 2025 15:27:22 +1200 Subject: [PATCH 5/5] fixed ci for http feature dep --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index be9f46b..a464f6d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,9 +30,9 @@ default = [ "rpc", ] mock-ffi = [] -http = ["rpc", "dep:serde"] +http = ["rpc", "dep:base64", "dep:serde"] llm = ["dep:serde"] -bless-crawl = ["http", "dep:base64", "dep:htmd", "dep:kuchikiki", "dep:regex", "dep:serde"] +bless-crawl = ["http", "dep:htmd", "dep:kuchikiki", "dep:regex", "dep:serde"] cgi = [] socket = [] memory = []