跳转到主要内容

WASM 插件(L3)

L3 插件以 WASM 模块形式运行在启动器 Rust 层(wasmtime 引擎)的沙箱中,适合 Agent、协议解析器、复杂逻辑等场景。与 L2(前端脚本)不同,L3 在独立运行时执行,不依赖浏览器环境。

一、工作原理

  • 启动器启动时,Rust 网关扫描 plugins/{插件id}/plugin.wasm(需 manifest layers 含 l3)
  • wasmtime 引擎加载模块,注入 host 函数(qomicex 模块),调用插件导出的函数
  • 网关端口写入 plugins/.gateway_port,后端 PluginGatewayClient 读取并代理
  • 前端通过 __PLUGIN_API__.callWasm(...) 经后端调用

二、插件结构

manifest 示例:
网关加载的是固定文件名 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:
src/lib.rs:
编译:

2. C / C++(可行)

plugin.c:
编译(需 clang + wasm-ld,如 wasi-sdk / LLVM):
  • 必须用 wasm32-unknown-unknown(非 wasm32-wasi,后者会引入 WASI 导入)
  • -nostdlib 下无 memcpy/memset,用到需自行实现
  • -Wl,--export-memory 导出名为 memory 的线性内存

3. AssemblyScript(可行)

entry.ts:
编译(需 Node.js + assemblyscript):
AssemblyScript 默认导出名为 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 插件逻辑用 Rust / C / AssemblyScript 编写,宿主侧(前端或后端)用你熟悉的语言。

六、从插件/前端调用

权限:wasm:execute

七、后端代理端点

后端将网关能力代理为以下 HTTP 端点(前端 API 已封装):

八、注意事项

  • 插件包需包含 plugin.wasm,且 manifest layers 含 l3,才会被网关加载
  • plugin.wasm 是核心 wasm 模块(core module),非 WASI/component 模块
  • 数据目录与前端插件一致({数据目录}/plugins/{id}/),由 QOMICEX_HOME 或系统数据目录决定
  • 网关日志输出到启动器控制台([plugin] / [gateway] 前缀)
  • 当前 db_set/db_get 为网关进程内键值存储,重启清空;http_fetch/instance_list 预留