扩展运行机制

扩展运行机制

扩展运行机制

功能

扩展机制把“脚本能看到的 API”和“扩展内部如何执行”分开。脚本只通过 bindings.json 里声明的入口、对象和方法调用扩展;BT 宿主负责加载 .bts 包、校验描述文件、建立注册表,并把调用分发给对应 Runner。

语法

扩展入口调用语法和普通函数一致:

calc 来自 bindings.json 的公开入口声明,addvalue 来自对象方法声明。

参数

扩展调用的参数由 bindings 决定。宿主会按 bindings 的参数数量、类型和 role 处理脚本传入的值,再把调用交给对应 Runner。

返回值

扩展调用可以返回原始值,也可以返回扩展对象句柄。对象句柄只表示“某个扩展模块中的某个对象”,真实状态由扩展后端保存。

脚本可以用 type(object) 查看扩展对象在 bindings.json 中声明的对象类型名:

加载流程

项目启动时,BT 会按以下流程处理扩展:

1. 查找项目根目录下的 extensions/

2. 按文件名顺序读取目录中的 .bts 文件。

3. 校验 .bts 后缀、zip 条目路径、条目数量、单文件大小和总解压大小。

4. 读取并校验 manifest.json

5. 读取并校验 bindings.json

6. 根据 manifest.kindmanifest.runtime.mode 初始化纯 BT Runner、线程本地 WASM Runner 或项目级 ExtensionService。

7. 建立扩展注册表,检查公开入口名是否冲突。

8. 把公开入口注入到当前 VM 的用户全局环境。

加载失败时,项目启动会失败并输出中文错误;BT 不会加载半成功的扩展包。

调用流程

脚本调用扩展入口时:

宿主会按入口名 calc 找到 bindings 中的函数声明,检查参数数量和类型,再把调用交给扩展所属 Runner 或 shared 服务。返回值如果是普通值,就直接回到脚本;如果是扩展对象,脚本拿到的是一个受宿主管理的对象句柄。

脚本调用对象方法时,宿主会先根据对象句柄找到扩展模块和对象类型,再查找方法名。WASM 方法调用时,接收者对象句柄会作为第一个参数传给 WASM;纯 BT 方法调用时,宿主会在内部 VM 中把方法调用到对应对象上。

runtime.mode=shared 的 WASM 扩展会把参数先编码成 BtValueBinary 字节,再投递到项目级 ExtensionService 的有界 worker 队列。worker 线程只接收调用 ID、返回类型、调用标签、参数字节和回复通道,返回结果字节后由调用线程解码,避免把 VM 内部 Value 跨线程传递。

shared 扩展返回对象时,worker 返回的是本地对象 ID。宿主会把它登记为脚本可见的 host_object_id,并记录 host_object_id -> worker_id + local_object_id + type_id。后续对象方法调用会先查这张表,把接收者改回 worker 本地对象 ID,并投递到创建该对象的 worker。lifecycle=dispose 的方法成功返回后,宿主会移除这条路由。

shared worker 使用 Wasmtime epoch interrupt 处理 call_timeout_ms。调用超时时,调用线程会标记目标 worker 并推进模块 Engine 的 epoch;只有被标记的 worker 会在 epoch callback 中返回超时 trap。该 worker 随后清理超时标记、丢弃旧 Store/Instance 并重建运行态,其他 worker 会继续执行。

如果 WASM 模块导出 bts_initbts_shutdownbts_stats,Runner 会在 worker 初始化、正常退出或统计读取路径调用它们;未导出这些函数的旧扩展保持兼容。

kind 和 abi

kind 是后端类型,决定入口文件由谁执行。abi 是调用协议版本,决定宿主和后端如何交换参数、返回值和对象句柄。

kindabiRunner
btbts-bt-1纯 BT Runner,复用 BT Parser、Compiler 和 VM。
wasmbts-wasi-1线程本地 WASM Runner 或 shared ExtensionService,使用 WASI P1 和 BtValueBinary。

这两个字段不能随意组合。kind=bt 必须使用 bts-bt-1kind=wasm 必须使用 bts-wasi-1

代码示例

同一个 bindings.json 风格可以对应不同后端。脚本侧调用保持一致:

差别只在扩展包内部:纯 BT 扩展由 src/lib.bt 实现;WASM 扩展由 module.wasm 实现。

注意事项

  • 公开入口会成为全局常量,脚本不能重新赋值。
  • env('calc') 可以读取扩展入口,has_env('calc') 返回 true
  • envs('calc')has_envs('calc') 只表示系统函数和系统常量,不会把扩展入口当作系统能力。
  • 扩展入口名不能和 BT 系统环境名称冲突,也不能和其他扩展入口重复。
  • type() 返回扩展对象的脚本可见类型名,例如 Calc;真实方法路由仍由宿主根据模块 ID、类型 ID 和对象 ID 完成。
  • 扩展对象不应跨越不支持对象句柄的边界,例如 task() 快照。
  • shared WASM 使用宿主级对象句柄表路由对象方法;旧句柄或已释放句柄会返回已失效错误。
  • shared WASM 超时中断只保证不会让 worker 永久占用服务容量;如果 WASM 正在执行长期阻塞 hostcall,仍需要后续 host import 自身提供取消边界。