Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ 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 }
json = { version = "0.12", default-features = false }
kuchikiki = { version = "0.8", default-features = false }
Expand Down
38 changes: 6 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,7 @@
2. Use follow command for build the project.

```bash
$ cargo build
```

HTTP example

```rust
use blockless_sdk::*;
use json;

fn main() {
let opts = HttpOptions::new("GET", 30, 10);
let http = BlocklessHttp::open("https://demo.bls.dev/tokens", &opts);
let http = http.unwrap();
let body = http.get_all_body().unwrap();
let body = String::from_utf8(body).unwrap();
let tokens = match json::parse(&body).unwrap() {
json::JsonValue::Object(o) => o,
_ => panic!("must be object"),
};
let tokens = match tokens.get("tokens") {
Some(json::JsonValue::Array(tokens)) => tokens,
_ => panic!("must be array"),
};
tokens.iter().for_each(|s| {
println!("{:?}", s.as_str());
});
}
cargo build --release --target wasm32-wasip1
```

## Install from [crates.io](https://crates.io/crates/blockless-sdk)
Expand All @@ -58,14 +32,14 @@ cargo build --release --target wasm32-wasip1 --example coingecko_oracle
echo "bitcoin" | runtime target/wasm32-wasip1/release/examples/coingecko_oracle.wasm --permission https://api.coingecko.com/
```

### [HTTP](./examples/httpbin.rs)
### [HTTP](./examples/http_client.rs)

```sh
# Build example
cargo build --release --target wasm32-wasip1 --example httpbin
cargo build --release --target wasm32-wasip1 --example http_client

# Run example with blockless runtime
~/.bls/runtime/bls-runtime target/wasm32-wasip1/release/examples/httpbin.wasm --permission http://httpbin.org/anything
~/.bls/runtime/bls-runtime target/wasm32-wasip1/release/examples/http_client.wasm --permission http://httpbin.org/anything
```

### [LLM-MCP](./examples/llm-mcp.rs)
Expand All @@ -83,8 +57,8 @@ cargo build --release --target wasm32-wasip1 --example llm-mcp

| Example | Description | [Browser runtime](https://github.com/blocklessnetwork/b7s-browser) support | [Native runtime](https://github.com/blessnetwork/bls-runtime) support |
| ------- | ----------- | --------------- | --------------- |
| [coingecko_oracle](./examples/coingecko_oracle.rs) | Coingecko Oracle to query price of bitcoin from coingecko | ✅ | |
| [httpbin](./examples/httpbin.rs) | HTTP to query anything from httpbin | ✅ | |
| [coingecko_oracle](./examples/coingecko_oracle.rs) | Coingecko Oracle to query price of bitcoin from coingecko | ✅ | |
| [http_client](./examples/http_client.rs) | HTTP client demonstrating various request types (GET, POST, auth, multipart) | ✅ | |
| [llm](./examples/llm.rs) | LLM to chat with `Llama-3.1-8B-Instruct-q4f32_1-MLC` and `SmolLM2-1.7B-Instruct-q4f16_1-MLC` models | ✅ | ✅ |
| [llm-mcp](./examples/llm-mcp.rs) | LLM with MCP (Model Control Protocol) demonstrating tool integration using SSE endpoints | ✅ | ✅ |
| [web-scrape](./examples/web-scrape.rs) | Web Scraping to scrape content from a single URL with custom configuration overrides | ✅ | ❌ |
Expand Down
21 changes: 9 additions & 12 deletions examples/coingecko_oracle.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use blockless_sdk::*;
use blockless_sdk::http::HttpClient;
use blockless_sdk::read_stdin;
use serde_json::json;
use std::collections::HashMap;

Expand All @@ -19,17 +20,13 @@ fn main() {
.trim();

// perform http request
let http_opts = HttpOptions::new("GET", 30, 10);
let http_res = BlocklessHttp::open(
format!(
"https://api.coingecko.com/api/v3/simple/price?ids={}&vs_currencies=usd",
coin_id
)
.as_str(),
&http_opts,
)
.unwrap();
let body = http_res.get_all_body().unwrap(); // e.g. {"bitcoin":{"usd":67675}}
let client = HttpClient::new();
let url = format!(
"https://api.coingecko.com/api/v3/simple/price?ids={}&vs_currencies=usd",
coin_id
);
let response = client.get(&url).send().unwrap();
let body = response.bytes().to_vec(); // e.g. {"bitcoin":{"usd":67675}}

// println!("{}", String::from_utf8(body.clone()).unwrap());

Expand Down
175 changes: 175 additions & 0 deletions examples/http_client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
use blockless_sdk::http::{get, post, HttpClient, MultipartField};
use std::collections::HashMap;

fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("====================================");
println!("HTTP v2 Client Demo");
println!("====================================");

println!("\n1. GET request:");
match get("https://httpbin.org/get").send() {
Ok(response) => {
println!("GET Status: {}", response.status());
println!("GET Success: {}", response.is_success());
}
Err(e) => println!("GET Error: {}", e),
}

println!("\n2. POST with JSON:");
let json_data = serde_json::json!({
"name": "Blockless SDK",
"version": "2.0",
"api_style": "reqwest-like"
});
match post("https://httpbin.org/post").json(&json_data)?.send() {
Ok(response) => {
println!("POST JSON Status: {}", response.status());
if let Ok(response_json) = response.json::<serde_json::Value>() {
if let Some(received_json) = response_json.get("json") {
println!("Received JSON: {}", received_json);
}
}
}
Err(e) => println!("POST JSON Error: {}", e),
}

println!("\n3. Client instance with default configuration:");
let mut default_headers = HashMap::new();
default_headers.insert("User-Agent".to_string(), "Blockless-SDK/2.0".to_string());
default_headers.insert("Accept".to_string(), "application/json".to_string());
let client = HttpClient::builder()
.default_headers(default_headers)
.timeout(10000)
.build();
match client
.get("https://httpbin.org/get")
.query("search", "blockless")
.query("limit", "10")
.query("format", "json")
.send()
{
Ok(response) => {
println!("Client GET Status: {}", response.status());
if let Ok(json_data) = response.json::<serde_json::Value>() {
if let Some(args) = json_data.get("args") {
println!("Query params: {}", args);
}
}
}
Err(e) => println!("Client GET Error: {}", e),
}

println!("\n4. Authentication examples:");
match client
.get("https://httpbin.org/basic-auth/user/pass")
.basic_auth("user", "pass")
.send()
{
Ok(response) => {
println!("Basic auth status: {}", response.status());
if let Ok(json_data) = response.json::<serde_json::Value>() {
println!("Authenticated: {:?}", json_data.get("authenticated"));
}
}
Err(e) => println!("Basic auth error: {}", e),
}

match client
.get("https://httpbin.org/bearer")
.bearer_auth("test-token-12345")
.send()
{
Ok(response) => {
println!("Bearer auth status: {}", response.status());
if let Ok(json_data) = response.json::<serde_json::Value>() {
println!("Token received: {:?}", json_data.get("token"));
}
}
Err(e) => println!("Bearer auth error: {}", e),
}

println!("\n5. Different request body types:");
let mut form_data = HashMap::new();
form_data.insert("name".to_string(), "Blockless".to_string());
form_data.insert("type".to_string(), "distributed computing".to_string());
match client
.post("https://httpbin.org/post")
.form(form_data)
.send()
{
Ok(response) => {
println!("Form POST Status: {}", response.status());
if let Ok(json_data) = response.json::<serde_json::Value>() {
if let Some(form) = json_data.get("form") {
println!("Form data received: {}", form);
}
}
}
Err(e) => println!("Form POST Error: {}", e),
}

println!("\n6. Multipart form with file upload:");
let multipart_fields = vec![
MultipartField::text("description", "SDK test file"),
MultipartField::file(
"upload",
b"Hello from Blockless SDK v2!".to_vec(),
"hello.txt",
Some("text/plain".to_string()),
),
];
match client
.post("https://httpbin.org/post")
.multipart(multipart_fields)
.send()
{
Ok(response) => {
println!("Multipart POST Status: {}", response.status());
if let Ok(json_data) = response.json::<serde_json::Value>() {
if let Some(files) = json_data.get("files") {
println!("Files uploaded: {}", files);
}
}
}
Err(e) => println!("Multipart POST Error: {}", e),
}

println!("\n7. Binary data:");
let binary_data = vec![0x48, 0x65, 0x6c, 0x6c, 0x6f]; // "Hello" in bytes
match client
.post("https://httpbin.org/post")
.header("Content-Type", "application/octet-stream")
.body_bytes(binary_data)
.send()
{
Ok(response) => {
println!("Binary POST Status: {}", response.status());
}
Err(e) => println!("Binary POST Error: {}", e),
}

println!("\n8. Advanced request building:");
match client
.put("https://httpbin.org/put")
.header("X-Custom-Header", "custom-value")
.header("X-API-Version", "2.0")
.query("action", "update")
.query("id", "12345")
.timeout(5000)
.body("Updated data")
.send()
{
Ok(response) => {
println!("PUT Status: {}", response.status());
if let Ok(json_data) = response.json::<serde_json::Value>() {
if let Some(headers) = json_data.get("headers") {
println!("Custom headers received: {}", headers);
}
}
}
Err(e) => println!("PUT Error: {}", e),
}

println!("\nDemo completed 🚀");
Ok(())
}
26 changes: 0 additions & 26 deletions examples/httpbin.rs

This file was deleted.

Loading
Loading