| Crates.io | weedforge |
| lib.rs | weedforge |
| version | 0.1.2 |
| created_at | 2026-01-08 04:00:02.969691+00 |
| updated_at | 2026-01-08 07:44:08.741267+00 |
| description | Rust-first, Python-friendly SDK for SeaweedFS |
| homepage | |
| repository | https://github.com/danghoangnhan/weedforge |
| max_upload_size | |
| id | 2029508 |
| size | 141,322 |
A lightweight Rust SDK with Python bindings for SeaweedFS.
FileId as a first-class entity, not an opaque string[dependencies]
weedforge = "0.1"
pip install weedforge
use weedforge::WeedClient;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create client with HA support
let client = WeedClient::builder()
.master_urls(["http://master1:9333", "http://master2:9333"])
.build()?;
// Upload a file
let file_id = client.write(b"Hello, SeaweedFS!".to_vec(), Some("hello.txt")).await?;
println!("Uploaded: {}", file_id);
// Download the file
let data = client.read(&file_id).await?;
println!("Downloaded: {} bytes", data.len());
// Get public URL
let url = client.public_url(&file_id).await?;
println!("Public URL: {}", url);
// Delete the file
client.delete(&file_id).await?;
Ok(())
}
use weedforge::BlockingWeedClient;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = BlockingWeedClient::builder()
.master_url("http://localhost:9333")
.build()?;
let file_id = client.write(b"Hello!".to_vec(), Some("hello.txt"))?;
let data = client.read(&file_id)?;
Ok(())
}
from weedforge import WeedClient, FileId
# Create client
client = WeedClient(
master_urls=["http://localhost:9333"],
strategy="round_robin", # or "failover", "random"
max_retries=3
)
# Upload bytes
file_id = client.write(b"Hello, SeaweedFS!", filename="hello.txt")
print(f"Uploaded: {file_id}")
# Download
data = client.read(file_id)
print(f"Downloaded: {len(data)} bytes")
# Get public URL
url = client.public_url(file_id)
print(f"Public URL: {url}")
# With image resize
url = client.public_url_resized(file_id, width=200, height=200)
# Delete
client.delete(file_id)
# Parse file ID from string
fid = FileId.parse("3,01637037d6")
print(f"Volume: {fid.volume_id}, Key: {fid.file_key}")
weedforge follows Clean Architecture principles:
┌─────────────────────────────────────────┐
│ Python Bindings │ ← Thin wrappers (PyO3)
├─────────────────────────────────────────┤
│ Application Layer │ ← Use cases (WriteFile, ReadFile)
├─────────────────────────────────────────┤
│ Domain Layer │ ← Entities (FileId), Ports (traits)
├─────────────────────────────────────────┤
│ Infrastructure Layer │ ← HTTP clients, HA logic
└─────────────────────────────────────────┘
Dependencies flow downward only:
| Strategy | Description |
|---|---|
round_robin |
Cycle through masters (default) |
failover |
Try masters in order, failover on error |
random |
Random selection |
let client = WeedClient::builder()
.master_urls(["http://master1:9333", "http://master2:9333"])
.strategy(MasterSelectionStrategy::RoundRobin)
.max_retries(3)
.http_config(HttpClientConfig::default()
.with_connect_timeout(Duration::from_secs(5))
.with_request_timeout(Duration::from_secs(30)))
.build()?;
weedforge implements the official SeaweedFS protocol:
GET /dir/assign → Get file ID and volume URLPOST {volume_url}/{fid} → Upload file (multipart)fid for storageGET /dir/lookup?volumeId=X → Get volume locationsGET {volume_url}/{fid} → Download file# Rust
cargo build --release
# Python (development)
cd crates/weedforge-python
maturin develop
# Python (release wheel)
maturin build --release
# Rust tests
cargo test
# Clippy
cargo clippy --all-targets --all-features
# Format check
cargo fmt --check
# Security audit
cargo deny check