宿主 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 秒)。
消息类型
拓展 → 宿主
| type | payload | 说明 |
|---|---|---|
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} | 写启动器设置 |
宿主 → 拓展
| type | payload | 说明 |
|---|---|---|
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); }生命周期建议
- 收到
hello后尽快回ready,别在握手阶段做重活。 - 长任务放后台线程,主线程保持读 stdin。
- 收到
shutdown主动退出,别等被杀。 - 别把 stdout 用来打调试日志——那是协议通道,日志走
log消息或 stderr。
限制
- 单条消息上限 1 MiB,超了会被截断并断开。
- 请求 10 秒无响应算超时。
- 每个拓展最多 4 个并发请求。
ui.page的 HTML 会被消毒:不允许<script>、on*属性、外部 iframe。
