HGhub 开发者HPP 1.0 草案

02 · 运行时

← 总览

本章定义插件代码的执行环境:能用什么、何时被加载、如何被调用、出错时如何表达。

1. 引擎

协议不绑定具体引擎,只规定环境契约。宿主必须满足:

实现建议(非规范):选用解释执行、不依赖 JIT 的可嵌入引擎(QuickJS 一系)。 它在五个平台上行为一致,可在 iOS 上使用,并原生支持内存上限与执行中断。 在 WebView 的 iframe 或 Worker 中运行插件不满足上述第 2、4 条。

独立调度保证一个插件的同步执行不占用界面线程或阻塞其他插件;可以使用专用线程或等效机制, 不要求每插件一个操作系统进程。本协议隔离脚本级死循环、超额分配与可恢复引擎错误, 不承诺在同进程内隔离原生引擎崩溃、进程被系统终止等故障。

2. 全局对象

2.1 保证存在

除 ES2022 标准内建对象外,宿主必须提供:

全局对象 说明
console debug / log / info / warn / error,等价于 hg.log.*
setTimeout、clearTimeout 归属于创建它的调用,随该调用结束清理;无 setInterval
queueMicrotask —
TextEncoder、TextDecoder 保证 UTF-8;其他字符集需特性 charset.legacy
URL、URLSearchParams WHATWG URL 语义
atob、btoa —
AbortController、AbortSignal —
structuredClone 仅支持可传递值
crypto.getRandomValues、crypto.randomUUID 密码学安全的随机源

2.2 保证不存在

fetch、XMLHttpRequest、WebSocket、DOM(window、document、navigator)、 localStorage / sessionStorage / indexedDB、WebAssembly、Worker、setInterval、 Node.js 的 require / process / Buffer。

联网用 hg.http,持久化用 hg.storage。

3. 入口

export const meta = { id: "demo", name: "示例源", version: "1.0.0", protocol: 1 };
export default function (hg) { /* 返回插件对象 */ }

4. 可传递值

宿主与插件之间传递的参数与返回值必须是可传递值:

规则:

以上限制适用于能力方法的业务参数、业务返回值与持久数据。以下为运行时绑定对象,不走可传递值序列化: hg、ctx(含 AbortSignal)、HttpRequest.signal、HtmlNode、错误对象与定时器回调。 它们不得嵌入业务返回值或存储。void 方法允许以 undefined 完成;数组元素不得为 undefined。 大小计算为:将每个 Uint8Array 替换成 null、丢弃 undefined 对象属性后,对紧凑 JSON 的 UTF-8 字节数, 再加全部二进制原始字节数;不能只计算 JS 字符数。这个定义用于预算,不要求桥接采用 JSON 编码。

5. 调用模型

5.1 方法形状

插件的能力方法与资源变换都是同一形状(卸载钩子 dispose 的例外见 06 §16):

method(params: object, ctx: CallContext): T | Promise<T>
字段 说明
requestId 调用标识,出现在宿主日志中
deadline 动态只读的截止时间(Unix 毫秒);网页视图暂停调用预算期间为 null
signal 取消信号:用户离开页面、调用被取代或到达截止时间时触发

宿主必须为每次调用建立任务作用域。调用内产生的 HTTP、网页视图、定时器及异步宿主操作 默认归属于该作用域,跨 await 与定时器回调仍保持归属,不能借同插件的另一次调用续命。 插件可透传 ctx.signal 或提供更早的取消信号;显式信号与调用取消取“任一触发即取消”,不能替代调用作用域。

方法完成、失败或被取消时,宿主停止其剩余任务,丢弃迟到结果,拒绝迟到回调继续发起宿主操作。 已经发给上游的写操作与已经完成的原子存储写入不会撤销;宿主不自动重试写操作。

5.2 截止时间

调用类别 默认预算 上限
列表、详情、搜索等读取 15 秒 30 秒
播放解析(含解析器) 20 秒 60 秒
登录提交 30 秒 60 秒
资源变换(transformResource) 5 秒 10 秒
工厂函数 5 秒 5 秒(不可调)

插件可以在 meta.timeouts(键为 read、playback、login、transform,单位秒)里调整预算, 用于上游偏慢的场景。宿主必须把声明值夹在 5 秒与上表的上限之间:放宽可以,突破上限不行。

超时后宿主放弃结果、触发 signal,并向界面返回 TIMEOUT。正常异步超时不算运行时故障; 同步执行超出预算被强制中断时,触发调用同样返回 TIMEOUT,但运行时须重建并累计故障次数。 排队时间计入调用预算;连续等待多步网络请求不得重置总预算。 网页视图暂停预算的例外见 04 §12:ctx.deadline 在暂停期间为 null,恢复后反映更新的截止时间。

5.3 并发

5.4 无状态约定

插件随时可能被卸载并重新加载:

6. 生命周期

已导入/停用 ──启用──▶ 初始化 ──能力与线路就绪──▶ 就绪
                      │                  │
                      │ 初始化失败/超时    │ 空闲超时 · 应用挂起 · 用户改动设置
                      ▼                  ▼
                   初始化失败          卸载(下次调用再加载)

就绪 ──同步执行中断/内存超限/可恢复引擎错误──▶ 运行时重建 ──连续 3 次──▶ 已停用(提示用户,可手动恢复)

7. 限额

宿主必须执行资源预算。下表区分协议固定上限与 HGhub 默认调度策略;默认策略可以调优, 不能作为插件推断设备性能的依据。改变协议固定上限按兼容规则处理。

资源 预算 性质
堆内存 64 MiB / 插件 HGhub 默认;包含绑定的 HTML 文档等宿主资源占用
调用栈 1 MiB HGhub 默认
单段同步执行(两次让出事件循环之间) 1 秒 HGhub 默认,中断后重建运行时
在途调用 8,排队 32 HGhub 默认(§5.3)
单次调用的参数或返回值 8 MiB 协议固定上限,含整个对象而非仅二进制字段
定时器 64 个,单个延迟 ≤ 60 秒 HGhub 默认,生命周期受调用预算约束
hg.storage 5 MiB / 插件;键 ≤ 256 字节;单值 ≤ 256 KiB 协议固定上限,不与 HTTP/媒体缓存共享
日志 每分钟 240 行;单行 ≤ 2 KiB;每插件保留最近 2000 行 HGhub 默认

网络相关限额见 03 §3 与 04 §2。

8. 错误模型

8.1 表达方式

插件通过抛出 hg.PluginError 表达可预期的失败:

throw new hg.PluginError("AUTH_REQUIRED", "请先登录");
throw new hg.PluginError("RATE_LIMITED", "请求过于频繁", { retryAfterSec: 30 });

8.2 错误码

错误码 含义 宿主的默认处理 可重试
AUTH_REQUIRED 需要登录 引导登录 登录后
AUTH_INVALID 凭据错误 在登录表单内提示 否
AUTH_EXPIRED 会话失效 清除登录态并引导重新登录 登录后
NOT_FOUND 内容不存在 提示;片库条目标记失效 否
CONTENT_LOCKED 内容存在但当前不可播放 展示原因;可尝试换播放线路或换源 否
RATE_LIMITED 被限流 在 retryAfterSec 内禁止重试并提示 等待后
UPSTREAM_ERROR 上游返回错误 提示;可重试 是
UPSTREAM_CHANGED 上游结构与插件预期不符 提示"插件需要更新",提供检查更新入口 否
INTERACTION_REQUIRED 需要用户完成验证等操作 提示进入插件页;宿主不从错误消息或 details 推断并自动打开网页 用户操作后
NETWORK 网络不可达、DNS、TLS 失败 提示检查网络 是
TIMEOUT 超过截止时间 提示;可重试 是
CANCELLED 调用被取消 静默 —
INVALID_ARGUMENT 参数不合法 写入日志 否
STORAGE_FULL 插件持久存储配额不足 提示清理该插件数据;不得自动清除登录态 清理后
UNSUPPORTED 能力或参数组合不被支持 静默或提示 否
INTERNAL 插件缺陷或未归类错误 提示"插件出错",可查看日志 是

8.3 UPSTREAM_ERROR 与 UPSTREAM_CHANGED

这个区别决定用户该做什么,插件应当认真区分:

9. 返回值校验

宿主把插件返回的数据交给界面之前必须校验:

10. 日志