Rust auf Wippy ausführen
Bauen Sie eine Rust-WebAssembly-Komponente, registrieren Sie sie bei Wippy und stellen Sie sie über Funktions-, CLI- und HTTP-Einträge bereit.
Klassifizierung: Ausführbares Tutorial mit einer externen Rust-Komponenten-Toolchain. Die Seite enthält WIT, Rust-Implementierung, Wippy-Registry, Workflow für Integritäts-Hashes, Befehle, erwartete Ergebnisse und Fehlerprüfungen.
Was wir bauen
Eine Rust-Komponente mit vier exportierten Funktionen:
- greet - Nimmt einen Namen entgegen, gibt eine Begrüßung zurück
- add - Addiert zwei Ganzzahlen
- fibonacci - Berechnet die n-te Fibonacci-Zahl
- list-files - Listet Dateien in einem gemounteten Verzeichnis auf
Die Wippy-Anwendung registriert diese Exports als aufrufbare Funktionen, CLI-Befehle und einen HTTP-Endpunkt.
Voraussetzungen
- Wippy-Runtime
v0.3.32a. - Rust-Toolchain mit dem Target
wasm32-wasip1. - Eine funktionierende C-Toolchain. Unter Linux benötigt
cargo-componentaußerdem die OpenSSL-Entwicklungsbibliotheken. - cargo-component 0.21.1, die für dieses Tutorial verwendete Version.
rustup target add wasm32-wasip1
cargo install cargo-component --version 0.21.1 --locked
Erstellen Sie das generierte Komponenten-Grundgerüst und die Wippy-Verzeichnisse:
mkdir rust-wasm-demo
cd rust-wasm-demo
cargo component new --lib demo
mkdir -p app/src/demo/wasm
In PowerShell:
New-Item -ItemType Directory -Path rust-wasm-demo
Set-Location rust-wasm-demo
cargo component new --lib demo
New-Item -ItemType Directory -Path app\src\demo\wasm -Force
cargo component new schreibt kompatible Dateien Cargo.toml, src/lib.rs und
WIT und erzeugt später src/bindings.rs neu. Lassen Sie die generierte Version von
wit-bindgen-rt mit dem installierten cargo-component gekoppelt. Das Tool bezeichnet
diese Schnittstelle als experimentell und garantiert keine Kompatibilität des
generierten Codes zwischen Versionen.
Projektstruktur
rust-wasm-demo/
├── demo/ # Rust component
│ ├── Cargo.toml
│ ├── wit/
│ │ └── world.wit # WIT interface
│ └── src/
│ ├── bindings.rs # generated by cargo-component
│ └── lib.rs # implementation
└── app/ # Wippy application
├── wippy.lock
└── src/
├── _index.yaml # Infrastructure
└── demo/
├── _index.yaml # CLI processes
└── wasm/
├── _index.yaml # WASM entries
└── demo_component.wasm # Compiled binary
Schritt 1: WIT-Schnittstelle erstellen
WebAssembly Interface Types (WIT) definiert den Vertrag zwischen Host und Gast.
Erstellen Sie demo/wit/world.wit:
package component:demo;
world demo {
export greet: func(name: string) -> string;
export add: func(a: s32, b: s32) -> s32;
export fibonacci: func(n: u32) -> u64;
export list-files: func(path: string) -> string;
}
Jeder Export wird zu einer Funktion, die Wippy aufrufen kann.
Schritt 2: In Rust implementieren
Behalten Sie die generierte Datei demo/Cargo.toml bei. Ihre Paketmetadaten müssen
auf component:demo verweisen und damit zum WIT-Paket passen; der Crate-Typ der
Bibliothek muss cdylib bleiben.
Erstellen Sie demo/src/lib.rs:
#[allow(warnings)]
mod bindings;
use bindings::Guest;
struct Component;
impl Guest for Component {
fn greet(name: String) -> String {
format!("Hello, {}!", name)
}
fn add(a: i32, b: i32) -> i32 {
a + b
}
fn fibonacci(n: u32) -> u64 {
if n <= 1 {
return n as u64;
}
let (mut a, mut b) = (0u64, 1u64);
for _ in 2..=n {
let next = a + b;
a = b;
b = next;
}
b
}
fn list_files(path: String) -> String {
let mut result = String::new();
match std::fs::read_dir(&path) {
Ok(entries) => {
for entry in entries {
match entry {
Ok(e) => {
let name = e.file_name().to_string_lossy().to_string();
let meta = e.metadata();
let (kind, size) = match meta {
Ok(m) => {
let kind = if m.is_dir() { "dir" } else { "file" };
(kind, m.len())
}
Err(_) => ("?", 0),
};
let line = format!("{:<6} {:>8} {}", kind, size, name);
println!("{}", line);
result.push_str(&line);
result.push('\n');
}
Err(e) => {
let line = format!("error: {}", e);
eprintln!("{}", line);
result.push_str(&line);
result.push('\n');
}
}
}
}
Err(e) => {
let line = format!("cannot read {}: {}", path, e);
eprintln!("{}", line);
result.push_str(&line);
result.push('\n');
}
}
result
}
}
bindings::export!(Component with_types_in bindings);
Das bindings-Modul wird von cargo-component aus der WIT-Definition generiert.
Schritt 3: Komponente bauen
cd demo
cargo component build --release
Dies erzeugt target/wasm32-wasip1/release/demo.wasm. Kopieren Sie es in Ihre Wippy-App:
mkdir -p ../app/src/demo/wasm
cp target/wasm32-wasip1/release/demo.wasm ../app/src/demo/wasm/demo_component.wasm
In PowerShell:
New-Item -ItemType Directory -Path ..\app\src\demo\wasm -Force
Copy-Item -LiteralPath target\wasm32-wasip1\release\demo.wasm `
-Destination ..\app\src\demo\wasm\demo_component.wasm
Ermitteln Sie den SHA-256-Hash für die Integritätsprüfung:
sha256sum ../app/src/demo/wasm/demo_component.wasm
In PowerShell:
(Get-FileHash ..\app\src\demo\wasm\demo_component.wasm -Algorithm SHA256).Hash.ToLowerInvariant()
Kopieren Sie die 64 kleingeschriebenen Hexadezimalzeichen in jedes Feld
YOUR_HASH_HERE unten. Das endgültige Feld muss die Form
sha256:<64-hex-characters> besitzen. Es ist der Hash der kopierten Binärdatei,
nicht der Rust-Quelle oder des ursprünglichen Build-Pfads.
Schritt 4: Wippy-Anwendung
Infrastruktur
Erstellen Sie app/src/_index.yaml:
version: "1.0"
namespace: demo
entries:
- name: gateway
kind: http.service
meta:
comment: HTTP server
addr: ":8090"
lifecycle:
auto_start: true
- name: api
kind: http.router
meta:
comment: Public API router
server: demo:gateway
prefix: /
- name: processes
kind: process.host
lifecycle:
auto_start: true
- name: terminal
kind: terminal.host
lifecycle:
auto_start: true
- name: policy
kind: security.policy
meta:
comment: Grants access to mounted filesystems and WASM functions
policy:
actions:
- fs.get
- funcs.call
resources: "*"
effect: allow
Das Einhängen eines Dateisystems in ein WASM-Modul und der Aufruf einer WASM-Funktion sind beides abgesicherte Aktionen. Die Richtlinie gewährt sie; Einträge, die sie benötigen, referenzieren sie.
WASM-Funktionen
Erstellen Sie app/src/demo/wasm/_index.yaml:
version: "1.0"
namespace: demo.wasm
entries:
- name: assets
kind: fs.directory
meta:
comment: Filesystem with WASM binaries
directory: ./src/demo/wasm
- name: greet_function
kind: function.wasm
meta:
comment: Greet function via payload transport
fs: demo.wasm:assets
path: /demo_component.wasm
hash: sha256:YOUR_HASH_HERE
method: greet
pool:
type: inline
- name: add_function
kind: function.wasm
meta:
comment: Add function via payload transport
fs: demo.wasm:assets
path: /demo_component.wasm
hash: sha256:YOUR_HASH_HERE
method: add
pool:
type: inline
- name: fibonacci_function
kind: function.wasm
meta:
comment: Fibonacci function via payload transport
fs: demo.wasm:assets
path: /demo_component.wasm
hash: sha256:YOUR_HASH_HERE
method: fibonacci
pool:
type: inline
Wichtige Punkte:
- Ein einzelner
fs.directory-Eintrag stellt die WASM-Binärdatei bereit. - Mehrere Funktionen referenzieren dieselbe Binärdatei mit unterschiedlichen
method-Werten. - Das Feld
hashprüft die Integrität der Binärdatei beim Laden. - Der Pool
inlineserialisiert Aufrufe durch eine warme Instanz. Er setzt den Ausführungszustand zwischen synchronen Aufrufen zurück; verwenden Sie einen anderen Pool-Typ, wenn Sie parallele Worker benötigen.
Funktionen mit WASI
Die list-files-Funktion greift auf das Dateisystem zu und benötigt daher WASI-Imports:
- name: list_files_function
kind: function.wasm
meta:
comment: Filesystem listing with WASI mounts
fs: demo.wasm:assets
path: /demo_component.wasm
hash: sha256:YOUR_HASH_HERE
method: list-files
imports:
- wasi:cli
- wasi:io
- wasi:clocks
- wasi:filesystem
wasi:
mounts:
- fs: demo.wasm:assets
guest: /data
pool:
type: inline
Der Abschnitt wasi.mounts bildet einen Wippy-Dateisystem-Eintrag auf einen Guest-Pfad ab. Innerhalb des WASM-Moduls zeigt /data auf das Verzeichnis demo.wasm:assets.
CLI-Befehle
Erstellen Sie app/src/demo/_index.yaml:
version: "1.0"
namespace: demo.cli
entries:
- name: wasm_cli_policy
kind: security.policy
policy:
actions:
- fs.get
resources:
- demo.wasm:assets
effect: allow
- name: ls
kind: process.wasm
meta:
comment: List files from mounted WASI filesystem
command:
name: ls
short: List files from mounted directory
security:
actor: {id: demo.cli:ls}
policies: [demo:policy]
fs: demo.wasm:assets
path: /demo_component.wasm
hash: sha256:YOUR_HASH_HERE
method: list-files
imports:
- wasi:cli
- wasi:io
- wasi:clocks
- wasi:filesystem
wasi:
mounts:
- fs: demo.wasm:assets
guest: /data
Der meta.command-Block registriert den Prozess als benannten CLI-Befehl. Der greet-Befehl benötigt keine WASI-Imports, da er nur String-Operationen verwendet. Der ls-Befehl benötigt Dateisystemzugriff und trägt daher zusätzlich den Sicherheitskontext, der das Einhängen gewährt.
HTTP-Endpunkt
Fügen Sie zu app/src/demo/wasm/_index.yaml hinzu:
- name: http_greet
kind: function.wasm
meta:
comment: Greet exposed via wasi-http transport
fs: demo.wasm:assets
path: /demo_component.wasm
hash: sha256:YOUR_HASH_HERE
method: greet
transport: wasi-http
pool:
type: inline
- name: http_greet_endpoint
kind: http.endpoint
meta:
comment: HTTP POST endpoint for WASM greet
router: demo:api
method: POST
path: /greet
func: http_greet
Der wasi-http-Transport bildet HTTP-Request/Response-Kontext auf WASM-Argumente und -Ergebnisse ab.
Schritt 5: Initialisieren und ausführen
cd app
wippy init
CLI-Befehle ausführen
# List available commands
wippy run list
Available commands:
greet Greet someone via WASM (demo.cli:greet)
ls List files from mounted directory (demo.cli:ls)
Run with: wippy run <command>
Argumente nach dem Befehlsnamen werden der exportierten Funktion als String-Parameter übergeben, sodass jeder Befehl genau die Argumente entgegennimmt, die seine WIT-Signatur deklariert:
# Run greet
wippy run greet World
Hello, World!
# Run ls to list mounted directory
wippy run ls /data
Der Befehl sollte mindestens demo_component.wasm mit seiner Dateigröße ausgeben
und mit Status 0 enden. Wippy gibt beliebige Rückgabe-Payloads von process.wasm
nicht aus; deshalb verwendet das CLI-Beispiel die Rust-Funktion, die nach WASI-stdout schreibt.
Als Dienst ausführen
wippy run
Dies startet den HTTP-Server auf Port 8090. Der wasi-http-Transport übergibt den Request-Body als einziges String-Argument der Funktion:
curl -X POST http://localhost:8090/greet -d 'World'
Hello, World!
Aus Lua aufrufen
WASM-Funktionen werden auf dieselbe Weise wie Lua-Funktionen aufgerufen. Der aufrufende Prozess benötigt funcs.call auf dem Ziel, was demo:policy gewährt:
local funcs = require("funcs")
local greeting, err = funcs.call("demo.wasm:greet_function", "World")
-- greeting: "Hello, World!"
local sum, err = funcs.call("demo.wasm:add_function", 6, 7)
-- sum: 13
local fib, err = funcs.call("demo.wasm:fibonacci_function", 10)
-- fib: 55
Fehlerbehebung und Bereinigung
- Wenn
cargo componentunbekannt ist, installieren Sie es und führen Siecargo component builderneut aus. Ein gewöhnlichescargo builderzeugt für diese Einrichtung nicht dieselben Bindings oder dieselbe Komponentenausgabe. - Eine vor dem ersten Build fehlende Datei
src/bindings.rsist normal. Fehlt sie nachcargo component build, konnten das WIT-Paket oder die Komponentenmetadaten nicht aufgelöst werden; beheben Sie diesen Build-Fehler vor dem Kopieren einer Binärdatei. WASM hash mismatchbedeutet, dass die Binärdatei nach der Hash-Berechnung geändert wurde oder ein Platzhalter verblieben ist. Kopieren Sie die Release-Binärdatei erneut, berechnen Sie den Digest neu und aktualisieren Sie jeden referenzierenden Eintrag.- Ein Fehler bei der Import-Instanziierung bedeutet, dass die Komponente ein nicht
im Eintrag enthaltenes Host-Profil importiert. Behalten Sie für die Dateisystembeispiele
die Imports
wasi:cli,wasi:io,wasi:clocksundwasi:filesystembei. cannot read /databedeutet, dass der Gastpfad unterwasi.mountsoder dessen Dateisystemeintrag nicht zur Registry passt.- Beenden Sie die HTTP-Runtime mit Strg+C. Rust-Buildausgaben verbleiben unter
demo/target/; entfernen Sie dieses Verzeichnis und die kopierte.wasm-Datei, um die generierten Artefakte zu bereinigen.
Nächste Schritte
- WASM-Übersicht — Übersicht über die WebAssembly-Runtime
- WASM-Funktionen — Referenz der Funktionskonfiguration
- WASM-Prozesse — Referenz der Prozesskonfiguration
- Host-Funktionen — Verfügbare WASI-Imports
- CLI-Referenz — Dokumentation der CLI-Befehle