Skip to content

Commit 5abf32f

Browse files
committed
add host http functions for wasm plugins and add hackernews fs
1 parent 7ccbf9b commit 5abf32f

22 files changed

Lines changed: 1550 additions & 9 deletions

File tree

agfs-server/examples/hellofs-wasm/agfs-wasm-ffi/Cargo.lock renamed to agfs-server/examples/agfs-wasm-ffi/Cargo.lock

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
File renamed without changes.
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
# AGFS WASM FFI
2+
3+
A safe, high-level Rust SDK for building AGFS filesystem plugins in WebAssembly.
4+
5+
## Overview
6+
7+
This library provides a complete abstraction layer for developing AGFS plugins in Rust/WASM. It handles all the low-level details of the WASM interface and provides a clean, type-safe API.
8+
9+
## Features
10+
11+
- **Safe Abstractions**: Minimal unsafe code, all hidden behind safe interfaces
12+
- **Easy to Use**: Simply implement a trait and export with a macro
13+
- **Type-Safe**: Strong typing for all filesystem operations
14+
- **Host FS Access**: Access to the host filesystem from WASM
15+
- **HTTP Client**: Make HTTP requests to external services
16+
- **Flexible**: Support for both read-only and read-write filesystems
17+
18+
## Quick Start
19+
20+
Add this to your `Cargo.toml`:
21+
22+
```toml
23+
[dependencies]
24+
agfs-wasm-ffi = { path = "../agfs-wasm-ffi" }
25+
26+
[lib]
27+
crate-type = ["cdylib"]
28+
29+
[profile.release]
30+
opt-level = "z"
31+
lto = true
32+
codegen-units = 1
33+
panic = "abort"
34+
```
35+
36+
## Example: Read-Only Filesystem
37+
38+
```rust
39+
use agfs_wasm_ffi::prelude::*;
40+
41+
#[derive(Default)]
42+
struct HelloFS;
43+
44+
impl ReadOnlyFileSystem for HelloFS {
45+
fn name(&self) -> &str {
46+
"hellofs"
47+
}
48+
49+
fn readme(&self) -> &str {
50+
"A simple Hello World filesystem"
51+
}
52+
53+
fn read(&self, path: &str, _offset: i64, _size: i64) -> Result<Vec<u8>> {
54+
match path {
55+
"/hello.txt" => Ok(b"Hello, World!\n".to_vec()),
56+
_ => Err(Error::NotFound),
57+
}
58+
}
59+
60+
fn stat(&self, path: &str) -> Result<FileInfo> {
61+
match path {
62+
"/" => Ok(FileInfo::dir("", 0o755)),
63+
"/hello.txt" => Ok(FileInfo::file("hello.txt", 14, 0o644)),
64+
_ => Err(Error::NotFound),
65+
}
66+
}
67+
68+
fn readdir(&self, path: &str) -> Result<Vec<FileInfo>> {
69+
match path {
70+
"/" => Ok(vec![FileInfo::file("hello.txt", 14, 0o644)]),
71+
_ => Err(Error::NotFound),
72+
}
73+
}
74+
}
75+
76+
export_plugin!(HelloFS);
77+
```
78+
79+
## Example: Read-Write Filesystem
80+
81+
```rust
82+
use agfs_wasm_ffi::prelude::*;
83+
use std::collections::HashMap;
84+
use std::cell::RefCell;
85+
86+
#[derive(Default)]
87+
struct MemFS {
88+
files: RefCell<HashMap<String, Vec<u8>>>,
89+
}
90+
91+
impl FileSystem for MemFS {
92+
fn name(&self) -> &str {
93+
"memfs"
94+
}
95+
96+
fn read(&self, path: &str, offset: i64, size: i64) -> Result<Vec<u8>> {
97+
let files = self.files.borrow();
98+
let data = files.get(path).ok_or(Error::NotFound)?;
99+
// ... handle offset and size
100+
Ok(data.clone())
101+
}
102+
103+
fn write(&mut self, path: &str, data: &[u8]) -> Result<Vec<u8>> {
104+
self.files.borrow_mut().insert(path.to_string(), data.to_vec());
105+
Ok(vec![])
106+
}
107+
108+
// ... implement other methods
109+
}
110+
111+
export_plugin!(MemFS);
112+
```
113+
114+
## Host Filesystem Access
115+
116+
Access the host filesystem from your WASM plugin:
117+
118+
```rust
119+
use agfs_wasm_ffi::prelude::*;
120+
121+
// Read from host filesystem
122+
let data = HostFS::read("/path/on/host/file.txt", 0, -1)?;
123+
124+
// Write to host filesystem
125+
HostFS::write("/path/on/host/output.txt", b"Hello")?;
126+
127+
// Get file info
128+
let info = HostFS::stat("/path/on/host/file.txt")?;
129+
130+
// List directory
131+
let entries = HostFS::readdir("/path/on/host/dir")?;
132+
```
133+
134+
## HTTP Client
135+
136+
Make HTTP requests from your WASM plugin:
137+
138+
```rust
139+
use agfs_wasm_ffi::prelude::*;
140+
141+
// Simple GET request
142+
let response = Http::get("https://api.example.com/data")?;
143+
let text = response.text()?;
144+
145+
// POST with JSON
146+
let data = serde_json::json!({"key": "value"});
147+
let response = Http::post_json("https://api.example.com/submit", &data)?;
148+
149+
// Custom request
150+
let response = Http::request(
151+
HttpRequest::post("https://api.example.com/upload")
152+
.header("Authorization", "Bearer token")
153+
.body_str("data")
154+
.timeout(60)
155+
)?;
156+
157+
// Parse JSON response
158+
#[derive(Deserialize)]
159+
struct ApiResponse {
160+
status: String,
161+
}
162+
163+
let api_response: ApiResponse = response.json()?;
164+
```
165+
166+
## API Reference
167+
168+
### Traits
169+
170+
- **`ReadOnlyFileSystem`**: Implement for read-only filesystems
171+
- Required: `name()`, `read()`, `stat()`, `readdir()`
172+
- Optional: `readme()`, `initialize()`
173+
174+
- **`FileSystem`**: Implement for read-write filesystems
175+
- All ReadOnlyFileSystem methods
176+
- Additional: `write()`, `create()`, `mkdir()`, `remove()`, etc.
177+
178+
### Types
179+
180+
- **`FileInfo`**: File metadata (name, size, mode, timestamps)
181+
- **`Error`**: Filesystem errors (NotFound, PermissionDenied, etc.)
182+
- **`Config`**: Plugin configuration passed during initialization
183+
- **`HttpRequest`**: HTTP request builder
184+
- **`HttpResponse`**: HTTP response with status, headers, body
185+
186+
### Macros
187+
188+
- **`export_plugin!(Type)`**: Export your filesystem as a WASM plugin
189+
190+
## Building
191+
192+
Build your WASM plugin:
193+
194+
```bash
195+
cargo build --release --target wasm32-unknown-unknown
196+
```
197+
198+
Optimize with `wasm-opt` (optional):
199+
200+
```bash
201+
wasm-opt -Oz target/wasm32-unknown-unknown/release/your_plugin.wasm \
202+
-o optimized.wasm
203+
```
204+
205+
## Examples
206+
207+
See the `examples/` directory for complete examples:
208+
209+
- **hellofs-wasm**: Simple read-only filesystem with host FS access
210+
- **hackernewsfs-wasm**: Fetches Hacker News stories via HTTP
211+
212+
## License
213+
214+
Apache-2.0
File renamed without changes.

agfs-server/examples/hellofs-wasm/agfs-wasm-ffi/src/filesystem.rs renamed to agfs-server/examples/agfs-wasm-ffi/src/filesystem.rs

File renamed without changes.

agfs-server/examples/hellofs-wasm/agfs-wasm-ffi/src/host_fs.rs renamed to agfs-server/examples/agfs-wasm-ffi/src/host_fs.rs

File renamed without changes.

0 commit comments

Comments
 (0)