Skip to content

宿主 API ​

拓展与启动器之间走 stdio 上的行分隔 JSON(NDJSON):一行一条消息,UTF-8,不带 BOM。

协议 ​

启动器 → 拓展:

json
{"type":"hello","host":"1.1.37","dataDir":"C:\\...\\PCL"}

拓展 → 启动器:

json
{"type":"ready","name":"Hello Go"}

之后双向都是 {"type": "...", "id": "...", "payload": {...}}。带 id 的请求必须回同样 id 的响应,宿主有超时(默认 10 秒)。

消息类型 ​

拓展 → 宿主 ​

typepayload说明
ready{name}初始化完成
notify{title, text, level}弹通知,level = info / warn / error
log{text}写拓展日志
fs.read{path}读文件(需 fs.read)
fs.write{path, data}写文件(需 fs.write,data 为 base64)
http{method, url, headers, body}发请求(需 net)
instances{}取实例列表(需 fs.read)
versions{}取版本列表
launch{instance, version}触发启动(需 launch)
ui.page{title, html}加一个自定义页(需 ui)
settings.get{key}读启动器设置
settings.set{key, value}写启动器设置

宿主 → 拓展 ​

typepayload说明
hello{host, dataDir, locale}握手,第一条
resp{ok, data, error}对请求的响应
event{name, data}事件:launch.before / launch.after / instance.created / shutdown
ping{}保活,30 秒一次,回 pong

权限校验 ​

每次调用都按 manifest.json 的 permissions 检查。缺权限返回:

json
{"type":"resp","id":"7","payload":{"ok":false,"error":"permission denied: net"}}

Go 示例 ​

go
package main

import tmlext "github.com/TYWStudio/TML/extensions/sdk/go"

// 业务入口:两个方法都可以留空
type ext struct{}

func (ext) Ready() {
	tmlext.Log("info", "拓展已加载")
	tmlext.Toast("Hello")
}

func (ext) OnEvent(e tmlext.Event) {
	tmlext.Log("info", e.Type)
}

func main() { tmlext.Run(ext{}) }

Rust 示例 ​

rust
use tml_ext::{Event, Ext, Handler};

struct Ext0;

impl Handler for Ext0 {
    fn ready(&mut self, ext: &mut Ext) {
        ext.log("info", "拓展已加载");
        ext.toast("Hello");
    }

    fn event(&mut self, ext: &mut Ext, ev: Event) {
        ext.log("info", &ev.kind);
    }
}

fn main() { tml_ext::run(Ext0); }

生命周期建议 ​

  1. 收到 hello 后尽快回 ready,别在握手阶段做重活。
  2. 长任务放后台线程,主线程保持读 stdin。
  3. 收到 shutdown 主动退出,别等被杀。
  4. 别把 stdout 用来打调试日志——那是协议通道,日志走 log 消息或 stderr。

限制 ​

  • 单条消息上限 1 MiB,超了会被截断并断开。
  • 请求 10 秒无响应算超时。
  • 每个拓展最多 4 个并发请求。
  • ui.page 的 HTML 会被消毒:不允许 <script>、on* 属性、外部 iframe。