Overview
This example demonstrates MoFA’s WebAssembly plugin runtime for high-performance, sandboxed plugin execution. It showcases:
- Creating and compiling WASM modules
- Plugin lifecycle management
- Resource limits and sandboxing
- Math operations and recursive functions
- Plugin manager for multi-plugin coordination
- Performance metrics and monitoring
What You’ll Learn
- Using
WasmRuntime for WASM execution
- Writing WAT (WebAssembly Text) modules
- Implementing resource limits
- Plugin manager patterns
- Memory management in WASM
- Performance optimization
Prerequisites
- Rust 1.75 or higher
- Understanding of WebAssembly concepts
- Basic knowledge of WAT syntax
Architecture
Source Code
The example contains 393 lines with 4 different demonstrations. Here are the key parts:
use mofa_sdk::plugins::wasm_runtime::{
RuntimeConfig, WasmRuntime, WasmPluginConfig
};
// Create runtime
let mut rt_config = RuntimeConfig::new();
rt_config.execution_config.fuel_metering = false;
rt_config.execution_config.epoch_interruption = false;
let runtime = WasmRuntime::new(rt_config)?;
// Simple WAT module
let wat = r#"
(module
(func (export "answer") (result i32)
i32.const 42
)
(func (export "double") (param i32) (result i32)
local.get 0
i32.const 2
i32.mul
)
)
"#;
// Compile module
let compiled = runtime.compile_wat("basic-module", wat).await?;
info!("Compiled: {} bytes in {}ms",
compiled.size_bytes,
compiled.compile_time_ms
);
// Create plugin
let mut config = WasmPluginConfig::new("basic-plugin");
config.resource_limits.max_fuel = None;
let plugin = runtime.create_plugin(&compiled, config).await?;
// Initialize and execute
plugin.initialize().await?;
let result = plugin.call_i32("answer", &[]).await?;
info!("Result: {}", result); // 42
let result = plugin.call_i32("double", &[Val::I32(21)]).await?;
info!("Result: {}", result); // 42
Running the Example
cd examples/wasm_plugin
cargo run
Expected Output
╔══════════════════════════════════════════════════════════════╗
║ MoFA WASM Plugin Runtime Example ║
╚══════════════════════════════════════════════════════════════╝
📦 Example 1: Basic WASM Runtime
─────────────────────────────────────────────
✓ Compiled module: basic-module
Size: 84 bytes
Compile time: 15ms
✓ Created plugin: basic-plugin
State: Ready
✓ Called 'answer' function
Result: 42
✓ Called 'double' function with 21
Result: 42
📊 Plugin metrics:
Calls: 2
Success: 2
Avg time: 125ns
🔢 Example 2: Math Operations Plugin
─────────────────────────────────────────────
✓ Math plugin initialized
✓ add(10, 20) = 30 (expected: 30)
✓ sub(50, 20) = 30 (expected: 30)
✓ mul(6, 7) = 42 (expected: 42)
✓ factorial(5) = 120 (expected: 120)
✓ fibonacci(10) = 55 (expected: 55)
🔌 Example 3: Plugin Manager
─────────────────────────────────────────────
✓ Loaded plugin: greeter
✓ Loaded plugin: counter
📋 Loaded plugins: ["greeter", "counter"]
✓ All plugins initialized
📢 Greeting length: 13
🔢 Counter increment 1: 1
🔢 Counter increment 2: 2
🔢 Counter increment 3: 3
🔢 Counter increment 4: 4
🔢 Counter increment 5: 5
📊 Manager stats:
Active plugins: 2
Total calls: 6
Total execution time: 2ms
⚙️ Example 4: Resource Limits
─────────────────────────────────────────────
✓ Runtime created with restrictive limits
Max memory: 1MB (16 pages)
Max execution time: 1000ms
📏 Initial memory size: 1 page(s) (64KB)
✓ Written 42 to address 0, read back: 42
╔══════════════════════════════════════════════════════════════╗
║ All examples completed! ║
╚══════════════════════════════════════════════════════════════╝
Key Concepts
WAT vs Compiled Plugins
WAT Modules
Pre-compiled WASM
Write plugins in WebAssembly Text format:(module
(func (export "my_func") (param i32) (result i32)
local.get 0
i32.const 10
i32.add
)
)
Pros: Human-readable, easy to write
Cons: Must be compiled at runtime Compile from Rust or other languages:// Rust code compiled to WASM
#[no_mangle]
pub extern "C" fn my_func(x: i32) -> i32 {
x + 10
}
Pros: Better performance, use any language
Cons: Requires build step
Resource Limits
WASM plugins are sandboxed with configurable limits:
ResourceLimits {
max_memory_pages: 16, // Max 1MB memory
max_table_elements: 1000, // Max function table size
max_instances: 5, // Max plugin instances
max_execution_time_ms: 1000, // 1 second timeout
max_fuel: Some(1_000_000), // Instruction limit
max_call_depth: 100, // Max recursion depth
}
Plugin Lifecycle
// Create
let plugin = runtime.create_plugin(&compiled, config).await?;
// Initialize
plugin.initialize().await?;
// State: Initialized
// Execute
let result = plugin.call_i32("func", &args).await?;
// State: Running
// Stop
plugin.stop().await?;
// State: Stopped
Advanced Features
Memory Management
(module
(memory (export "memory") 2) ; 2 pages = 128KB
(func (export "alloc") (param $size i32) (result i32)
;; Simple bump allocator
;; Returns pointer to allocated memory
)
(func (export "free") (param $ptr i32)
;; Free allocated memory
)
)
Host Functions
// Define host function
let linker = wasmtime::Linker::new(&engine);
linker.func_wrap(
"env",
"log",
|caller: Caller<'_, ()>, ptr: i32, len: i32| {
// Read string from WASM memory
let memory = caller.get_export("memory").unwrap();
// Log the string
}
)?;
Plugin Events
let mut event_rx = manager.subscribe();
tokio::spawn(async move {
while let Ok(event) = event_rx.recv().await {
match event {
PluginEvent::Loaded { id } => {
info!("Plugin {} loaded", id);
}
PluginEvent::ExecutionCompleted { id, duration } => {
info!("Plugin {} completed in {:?}", id, duration);
}
_ => {}
}
}
});
| Plugin Type | Startup | Execution | Isolation | Hot Reload |
|---|
| Rhai | Fast | Slow | Partial | Yes |
| WASM | Medium | Fast | Full | No |
| Native | Instant | Fastest | None | No |
Use WASM for: Performance-critical code, untrusted plugins, cross-platform compatibilityUse Rhai for: Business logic, hot-reloadable rules, rapid iteration
Common Use Cases
Image Processing
High-performance image filters and transformations
Data Validation
Fast validation rules with sandboxing
Cryptography
Secure cryptographic operations
Game Logic
Sandboxed game mechanics
Troubleshooting
Problem: WAT module won’t compileSolution: Validate WAT syntax:# Use wat2wasm to check syntax
wat2wasm module.wat
Problem: Plugin exceeds memory limitSolution: Increase memory pages:config.resource_limits.max_memory_pages = 32; // 2MB
Problem: Cannot call exported functionSolution: Check export name:(func (export "exact_name") ...)
Best Practices
Compile Once: Cache compiled modules for reuse
Resource Limits: Always set appropriate limits for security
Error Handling: Trap WASM errors gracefully
Memory Safety: WASM memory is isolated but shared within the instance
Next Steps
Rhai Hot Reload
Compare with runtime plugins
Plugin System
Complete plugin guide
WASM Guide
Advanced WASM techniques
WASM API
WASM runtime API reference