Skip to content

服务层 ​

服务是插件间协作的桥梁(对应 Service)。框架内置一组服务,插件可以提供服务给其他插件(provide),也可以声明依赖消费服务(inject)。

内置服务 ​

服务说明
store数据存储(弹幕 / 视频 / 字幕 / kv,与后台同源)
model动态表模型(ctx.model.define,见 数据模型)
app服务控制:version / pid / uptime() / getConfig() / saveConfig() / restart()
logger分级日志:debug/info/warn/error(scope, msg) + 环形缓冲
httpfetch 封装:get/post/json(带超时)
routerExpress 路由(ctx.router.get/post/use...)

在 manifest.inject 中声明的服务会直接挂到 ctx 上:

json
{ "inject": ["store", "model", "app", "logger", "http"] }
js
apply(ctx, config) {
  ctx.logger.info('hello', '版本 ' + ctx.app.version);
  ctx.app.uptime();
}

提供服务 ​

插件 A 注册服务,插件 B 声明依赖即可使用(对应 插件框架的 ctx.provide):

js
// 插件 A:openvideo-plugin-stats
module.exports = {
  name: 'stats',
  provide: ['danmuStats'],          // manifest 声明
  apply(ctx, config) {
    const state = { count: 0 };
    ctx.on('danmu:send', () => { state.count++; });
    ctx.provide('danmuStats', {
      count: () => state.count
    });
  }
};
js
// 插件 B:声明依赖
// package.json: "openvideoPlugin": { "inject": ["danmuStats"] }
module.exports = {
  apply(ctx, config) {
    setInterval(() => {
      ctx.danmuStats.count();       // 直接可用
    }, 60000);
  }
};

依赖解析规则 ​

  • 启用插件 B 时,自动按拓扑序先启用并加载提供 danmuStats 的插件 A
  • 循环依赖 → 明确报错
  • 依赖服务不存在(提供者未安装)→ 加载失败并给出清晰原因
  • 内置服务名不可被插件覆写(store/model/app/logger/router/http/version... 为保留名)

运行时获取 ​

未在 inject 中声明的服务,可随时通过 ctx.service(name) 获取:

js
const s = ctx.service('danmuStats');
if (s) s.count();

与插件框架的对应 ​

插件框架OpenVideoAPI
ctx.provide('name', service)同
inject: ['service']同(manifest.inject)
ctx.service 访问同
Service 生命周期(dispose 清理)ctx.on('dispose', ...) 手动清理

MIT License · Made with ♥ by yangyang8002