WASM 插件(L3)
L3 插件以 WASM 模块形式运行在启动器 Rust 层(wasmtime 引擎)的沙箱中,适合 Agent、协议解析器、复杂逻辑等场景。与 L2(前端脚本)不同,L3 在独立运行时执行,不依赖浏览器环境。一、工作原理
- 启动器启动时,Rust 网关扫描
plugins/{插件id}/plugin.wasm(需 manifestlayers含l3) - wasmtime 引擎加载模块,注入 host 函数(
qomicex模块),调用插件导出的函数 - 网关端口写入
plugins/.gateway_port,后端PluginGatewayClient读取并代理 - 前端通过
__PLUGIN_API__.callWasm(...)经后端调用
二、插件结构
plugin.wasm(位于 plugins/{插件id}/plugin.wasm),无需在 manifest 里声明路径。entry.backend 是保留字段(当前未使用),不要依赖。
三、插件导出函数(WASM → 启动器)
四、Host API(启动器 → WASM)
插件通过导入qomicex 模块的函数访问启动器能力:
- 字符串通过
(指针, 长度)传入,需要插件自行管理 wasm 线性内存 http_fetch/instance_list当前为预留(返回 -1),网络与实例访问请通过前端callBackend/proxyFetch实现
五、多语言编写示例
WASM 插件是裸 core module(非 WASI / 非 component),各语言可行性如下:公共约定(所有语言)
- 导出
on_load/on_unload(() -> ())供网关调用;自定义导出() -> ()或() -> i32 - 导入
qomicex模块的 host 函数(log/db_set/db_get/get_plugin_id) - 字符串通过
(指针, 长度)传递,指针是 wasm 线性内存偏移(i32),非宿主指针 - 线性内存需导出(约定名
memory),网关用caller.get_export("memory")读取 - 函数签名必须与 host 注册签名严格一致,否则实例化报错
1. Rust(已验证)
Cargo.toml:2. C / C++(可行)
plugin.c:- 必须用
wasm32-unknown-unknown(非wasm32-wasi,后者会引入 WASI 导入) -nostdlib下无memcpy/memset,用到需自行实现-Wl,--export-memory导出名为memory的线性内存
3. AssemblyScript(可行)
entry.ts:memory 的内存,与网关约定一致。--exportRuntime 导出 __new/__pin 等内存助手;体积敏感可用 --runtime stub。
4. Zig(可行)
plugin.zig:5. Go(受限,WASI 模式)
Go 只有js / wasip1 两个 wasm 目标,无裸 core module 目标。wasip1 产物带 Go runtime 并引入 WASI 导入,需网关注册 WASI 才能跑(当前网关未注册,不可用)。仅作参考:
6. C# / Python(不可用)
- C# (.NET):NativeAOT 不支持 wasm 目标;Mono 的 browser-wasm / wasi-wasm 产物是整个 .NET runtime(数 MB,WASI 符号),不是裸 core module,无法满足网关约定。
- Python:无 wasm 编译目标;Pyodide 等方案是”把 CPython 解释器移植到 wasm”,不是把你的代码编译成模块。
六、从插件/前端调用
wasm:execute
七、后端代理端点
后端将网关能力代理为以下 HTTP 端点(前端 API 已封装):八、注意事项
- 插件包需包含
plugin.wasm,且 manifestlayers含l3,才会被网关加载 plugin.wasm是核心 wasm 模块(core module),非 WASI/component 模块- 数据目录与前端插件一致(
{数据目录}/plugins/{id}/),由QOMICEX_HOME或系统数据目录决定 - 网关日志输出到启动器控制台(
[plugin]/[gateway]前缀) - 当前
db_set/db_get为网关进程内键值存储,重启清空;http_fetch/instance_list预留