跳转到主要内容Skip to content

插件系统的完整接口定义:Host API、Plugin API、消息协议 / 事件定义、错误码与权限清单

Host API(宿主向插件提供的服务) ​

API 版本:HOST_API_VERSION = 1(见 manifest apiVersion)

  • 追加式演进:新字段只能加在 mpl_host_api_t 的 ctx 之后,禁止插入中间,旧插件按旧偏移仍能正确读取
  • manifest minHostVersion 声明插件所需的最低宿主 API 版本,major 超过宿主版本即拒绝加载
  • 插件能力(capabilities)在 manifest 中声明,宿主在每次调用时强制检查,越权返回 MPL_ERR_PERMISSION

Native(C ABI,mpl_host_api_t) ​

c
typedef struct mpl_host_api {
    void (*log)(void *ctx, mpl_log_level_t level, const char *msg);
    mpl_result_t (*get_config)(void *ctx, const char *key, char *out, uint32_t *out_size);
    mpl_result_t (*set_config)(void *ctx, const char *key, const char *json_value);
    mpl_result_t (*emit_event)(void *ctx, const char *topic, const char *json_payload);
    mpl_result_t (*send_message)(void *ctx, const char *target_json, const uint8_t *payload, uint32_t payload_len);
    mpl_result_t (*audio_state)(void *ctx, char *out, uint32_t *out_size);
    mpl_result_t (*connected_devices)(void *ctx, char *out, uint32_t *out_size);
    void *ctx;
    /* 以下字段一律追加在 ctx 之后(追加式演进,见上) */
    mpl_result_t (*play_sound)(void *ctx, const char *path);
    mpl_result_t (*plugin_dir)(void *ctx, char *out, uint32_t *out_size);
    mpl_result_t (*register_hotkey)(void *ctx, const char *shortcut, uint64_t *out_id);
    mpl_result_t (*open_window)(void *ctx, const char *panel_id);
    mpl_result_t (*fs_read)(void *ctx, const char *path, char *out, uint32_t *out_size);
    mpl_result_t (*fs_write)(void *ctx, const char *path, const char *content);
    mpl_result_t (*set_timeout)(void *ctx, uint64_t ms, const char *payload, uint64_t *out_id);
    mpl_result_t (*clear_timeout)(void *ctx, uint64_t id);
    mpl_result_t (*http_request)(void *ctx, const char *method, const char *url,
                                 const char *headers_json, const char *body, uint64_t *out_id);
    mpl_result_t (*set_interval)(void *ctx, uint64_t ms, const char *payload, uint64_t *out_id);
    mpl_result_t (*clear_interval)(void *ctx, uint64_t id);
    mpl_result_t (*open_url)(void *ctx, const char *url);
    mpl_result_t (*notify)(void *ctx, const char *title, const char *body);
    mpl_result_t (*locale)(void *ctx, char *out, uint32_t *out_size);
    mpl_result_t (*host_info)(void *ctx, char *out, uint32_t *out_size);
    mpl_result_t (*clipboard_read)(void *ctx, char *out, uint32_t *out_size);
    mpl_result_t (*clipboard_write)(void *ctx, const char *text);
} mpl_host_api_t;

WASM(导入模块 micyou) ​

导入签名说明
log(level: i32, msg_ptr: i32) -> ()level:0=Error 1=Warn 2=Info 3=Debug 4=Trace
get_config(key_ptr: i32) -> i32返回宿主分配的 JSON 指针(0 = 无该键)
set_config(key_ptr: i32, value_json_ptr: i32) -> i32返回结果码
emit_event(topic_ptr: i32, payload_json_ptr: i32) -> i32返回结果码
send_message(target_json_ptr: i32, payload_ptr: i32, len: i32) -> i32返回结果码
audio_state() -> i32返回宿主分配的 JSON 指针
connected_devices() -> i32返回宿主分配的 JSON 数组指针
play_sound(path_ptr: i32) -> i32排队播放 WAV(需 audio.play),返回结果码
plugin_dir() -> i32返回插件安装目录绝对路径字符串
register_hotkey(shortcut_ptr: i32) -> i64注册全局快捷键(仅 X11 会话),返回句柄 id(0 = 失败)
open_window(panel_ptr: i32) -> i32打开插件自己的面板窗口
fs_read(path_ptr: i32) -> i32读取插件目录内文本文件(需 fs.read),返回字符串指针
fs_write(path_ptr: i32, content_ptr: i32) -> ()写文件(需 fs.write)
set_timeout(ms: i64, payload_ptr: i32) -> i64一次性定时器,返回 id
clear_timeout(id: i64) -> ()取消定时器
http_request(method_ptr, url_ptr, headers_ptr, body_ptr) -> i64异步 HTTP(需 network.io),返回请求 id
set_interval(ms: i64, payload_ptr: i32) -> i64循环定时器,返回 id
clear_interval(id: i64) -> ()停止循环定时器
open_url(url_ptr: i32) -> ()默认浏览器打开(需 open.url)
notify(title_ptr: i32, body_ptr: i32) -> ()系统通知
locale() -> i32宿主 UI 语言(如 zh-CN / en),字符串指针
host_info() -> i32宿主身份 JSON 字符串指针
clipboard_read() -> i32读剪贴板(需 clipboard.read)
clipboard_write(text_ptr: i32) -> ()写剪贴板(需 clipboard.write)

缓冲区契约(out / out_size) ​

  • out / out_size 描述插件提供的缓冲区(UTF-8)
  • 成功:写入 NUL 结尾字符串,*out_size = 字节数(不含 NUL),返回 MPL_OK
  • 缓冲区太小:*out_size = 所需大小,返回 MPL_ERR_BUFFER_TOO_SMALL
  • audio_state 返回 JSON 快照:
json
{ "streaming": true, "sampleRate": 48000, "channels": 1, "inputLevel": 0.42, "processedLevel": 0.38, "queuedMs": 12.5, "muted": false }
  • connected_devices 返回 JSON 数组:
json
[ { "mode": "wifi", "label": "MicYou Mobile", "audioActive": true } ]
  • host_info 返回:
json
{ "name": "micyou", "version": "2.0.0", "apiVersion": 1 }

play_sound(音频播放) ​

  • 参数为 WAV 文件路径,相对路径解析到插件自己的安装目录(插件可自带或动态生成音效文件)
  • 音效混入虚拟麦克风输出流(SoundMixer),对方与用户都能听到,等同于真实麦克风输入
  • 排队即返回,混音在输出设备线程完成,非实时安全,禁止在 process 中调用
  • 常见用法:ui 按钮面板(ui.route=buttons)点击 → handle_message 收到 ui:play → 查配置 → play_sound

register_hotkey(全局快捷键) ​

  • 参数为快捷键字符串(如 ctrl+shift+p),返回句柄 id
  • 按下时宿主经总线投递消息给插件:topic hotkey:<id>,payload {"shortcut":"..."}
  • 插件在 handle_message 中处理;进程退出自动注销
  • 快捷键格式由 global-hotkey 解析:修饰键 ctrl/alt/shift/super/cmd + 键名(字母、数字、f1-f12 等)
  • 平台限制:仅 X11 会话可用;Wayland 会话注册返回明确错误(合成器不转发 X11 全局抓取),请改用面板按钮

fs_read / fs_write(文件访问) ​

  • 读写插件自身安装目录内的 UTF-8 文本文件(需 fs.read / fs.write)
  • 路径沙箱:绝对路径与 .. 穿越一律拒绝(sandbox_path),插件无法触及目录外文件
  • fs_write 自动创建父目录
  • 常见用途:缓存、状态文件、生成资源(音效、脚本)、插件数据持久化

set_timeout / clear_timeout(一次性定时器) ​

  • set_timeout(ms, payload) 返回定时器 id,到期后宿主经总线投递: topic timer:expired,payload {"timer":<id>,"payload":"<payload>"}
  • 异步事件模型:定时器线程投递消息,不阻塞插件调用线程
  • clear_timeout(id) 取消尚未到期的定时器

set_interval / clear_interval(循环定时器) ​

  • set_interval(ms, payload) 返回循环定时器 id,每隔 ms 毫秒投递: topic interval:tick,payload {"interval":<id>,"payload":"<payload>"}
  • clear_interval(id) 停止;插件卸载时宿主自动停止其全部定时器

http_request(异步 HTTP) ​

  • http_request(method, url, headersJson, body) 返回请求 id(需 network.io)
  • 请求在宿主线程执行(10 秒超时),响应经总线异步投递: topic http:response,payload {"request":<id>,"ok":true,"status":200,"body":"...","error":null}
  • 失败时 ok=false 且 error 含原因
  • 插件不得在实时音频线程(process)中发起请求

open_url / notify(外部动作) ​

  • open_url(url):系统默认浏览器打开(需 open.url)
  • notify(title, body):系统通知(无能力要求)

locale / host_info(环境查询) ​

  • locale():宿主当前 UI 语言(如 zh-CN、en),插件面板据此切换自身文案
  • host_info():宿主身份与 API 版本,用于运行时兼容判断

clipboard_read / clipboard_write(剪贴板) ​

  • 读/写系统剪贴板文本(需 clipboard.read / clipboard.write)
  • 常见用途:自动化复制粘贴、把插件生成内容送剪贴板

事件投递(宿主 → 插件) ​

  • 设备连接/断开时宿主向所有已加载插件派发 PluginEvent::DeviceConnected(含 mode/label)与 DeviceDisconnected
  • 插件在 handle_event 中处理(native 为 micyou_plugin_handle_event,wasm 为 handle_event 导出)

Plugin API(插件向宿主实现的接口) ​

Native(C ABI 符号) ​

符号必需说明
micyou_plugin_info是返回静态 mpl_plugin_info_t,含 ABI / API 版本与 id
micyou_plugin_init(host)是保存 host 表,读取配置,返回结果码
micyou_plugin_deinit是清理(宿主卸载库前调用一次)
micyou_plugin_process(data, samples, channels, queued_ms, bypass)否实时 DSP
micyou_plugin_handle_event(type, json)否事件通知
micyou_plugin_handle_message(source, topic, payload, len)否跨端消息

WASM(导出) ​

导出必需说明
memory是线性内存
alloc / dealloc是内存分配(宿主写字符串 / 音频数据用)
api_version否返回 Host API 版本(1)
init否初始化,0 = 成功
process否DSP,0 = ok 1 = bypass
handle_event否事件(JSON 指针)
handle_message否跨端消息(指针, 长度)
deinit否反初始化

事件类型(PluginEvent) ​

事件负载
device_connected{ mode, label }
device_disconnected—
mute_changed{ muted }
dsp_settings_changed—
state_changed{ enabled }

消息协议 ​

线协议为 protobuf(crates/micyou-protocol/proto/network.proto),挂载在控制通道 MessageWrapper 字段 7:

proto
message PluginMessage {
    string source = 1;       // 发送方插件 id
    string target = 2;       // 接收方插件 id,"" = 广播
    string topic = 3;        // 主题
    bytes payload = 4;       // 插件自定义负载
    uint64 correlationId = 5;
    bool isResponse = 6;
    int32 errorCode = 7;     // 0 = ok
    string errorMessage = 8;
}

语义:

  • 发布订阅:target 为空,按 topic 分发(本地订阅者 + 远端广播)
  • 请求响应:correlationId 非 0 配对请求与响应;isResponse 标记响应
  • 错误响应:errorCode 非 0 + errorMessage

错误码 ​

PluginError 与 wire 错误码的稳定映射(改变即破坏兼容):

码含义
0ok
1not found(入口产物缺失)
2invalid manifest
3validation failed(清单语义校验)
4unknown plugin
5not loaded
6load failed
7api version mismatch
8permission denied(能力未授予)
9already exists
10runtime error(含 WASM trap / 燃料耗尽)
11message delivery failed(无设备 / 超时)
12io error

Native 的 mpl_result_t 数值与此保持一致(0-5 子集)

权限清单 ​

能力授予的 API风险
dsp.node处理链节点注册实时音频数据访问
config.readget_config插件自身配置
config.writeset_config插件自身配置
event.emitemit_event总线事件(含远端广播)
message.sendsend_message跨端消息
audio.stateaudio_state音频流状态快照
audio.playplay_sound播放 WAV 音效(异步,非实时)
device.listconnected_devices已连接设备信息
network.iohttp_request出站 HTTP(异步,10s 超时)
open.urlopen_url默认浏览器打开链接
clipboard.readclipboard_read读取剪贴板文本
clipboard.writeclipboard_write写入剪贴板文本
fs.readfs_read插件目录内文件读取(沙箱)
fs.writefs_write插件目录内文件写入(沙箱,自动建父目录)
register_hotkey无需能力全局快捷键(仅 X11,触发仅通知注册的插件)
无set_timeout/clear_timeout/set_interval/clear_interval定时器(不访问资源)
无notify/locale/host_info/plugin_dir/open_window通知与环境查询
  • 未知能力声明会被清单校验拒绝
  • 未声明能力的 API 调用被 host 回调层拒绝(MPL_ERR_PERMISSION / 错误码 8)
最后更新: · 本站内容随 妙有(MiCyou)工具 官方版本同步校对