ctx 上下文
ctx 在 setup(ctx) 时传入,之后随时可通过 self.ctx 访问。它是模块与宿主、与其他模块交互的唯一出口。
属性
| 属性 | 类型 | 说明 |
|---|---|---|
ctx.name | str | 模块名(等于 manifest 的 name) |
ctx.manifest | 清单对象 | 可读取 manifest 中的各字段 |
ctx.log | 日志器 | 名为 jade.module.<模块名>,输出到宿主日志栏 |
ctx.config | dict | 生效配置(manifest.config 与平台方覆盖合并),只读 |
ctx.store | 存储门面 | 本模块的持久化存储,见 持久化存储 |
方法部分(RPC、事件、外壳推送)见下文与 模块 API。
注册对外方法(RPC)
def setup(self, ctx):
ctx.register_handler("add", self._add) # 写法一:函数式
ctx.register_handler("add", lambda a, b: a + b)
@ctx.handler("mul") # 写法二:装饰器
def _mul(self, a, b): ...注册后即可被其他模块和前端调用:
# 别的模块
ctx.call("my_module", "add", 1, 2)// 你的页面
await jade.call("my_module", "add", 1, 2);注意:方法必须显式注册。 只在类里定义方法、不调 register_handler,调用方会收到 MethodNotFound。注册发生在 setup,不是 on_enable。
调用其他模块
ctx.call(target, method, *args, timeout=10.0, **kwargs) -> Any| 参数 | 说明 |
|---|---|
target | 目标模块名 |
method | 目标模块注册过的方法名 |
args / *kwargs | 位置 / 关键字参数 |
timeout | 超时秒数,默认 10 秒 |
- 同步阻塞,返回目标方法的返回值;超时或出错直接抛异常。
- 目标模块不在"运行中" → 抛
ModuleNotCallable。 - 目标没注册这个方法 → 抛
MethodNotFound。 - 目标模块不在你的
dependencies里 → 宿主开启严格模式后抛PermissionError。跨模块调用前一定要在 manifest 里声明依赖。 - 返回值与参数请保持 JSON 可序列化(
str/int/float/bool/None/list/dict)。不可序列化的对象会被转成字符串,前端拿到会莫名其妙。
事件(发布 / 订阅)
ctx.publish(topic: str, payload=None) -> None # 广播
ctx.subscribe(topic: str, fn) -> Callable # 订阅,回调 fn(payload, source)payload可以是任意 JSON 值;source是发布方的模块名。- 事件异步投递,某个订阅者出错不影响其他人。
- 主题名建议加模块名前缀避免冲突,例如
my_module/tick。 - 模块订阅自己发布的主题也会收到(与别的订阅者一视同仁)。
- 页面也能收事件(
jade.on(topic, fn),见 界面开发)。
ctx.subscribe("adb_monitor/update", self._on_update)
def _on_update(self, payload, source):
self.ctx.log.info("来自 %s 的更新: %s", source, payload)
ctx.publish("my_module/tick", {"ts": time.time()})配置
cfg = self.ctx.config # 只读 dict
interval = float(cfg.get("interval", 2.0))来源是 manifest 的 config 段,平台方可用自身配置覆盖同名键。配置只读。需要运行时可改、跨重启保存的设置,存进 ctx.store,在页面里提供修改入口。
日志
ctx.log.debug("明细 %s", payload) # 细粒度,默认不显示在主界面日志栏
ctx.log.info("已连接 %d 台设备", n) # 关键动作
ctx.log.warning("读取失败: %s", e)
ctx.log.error("初始化失败: %s", e)- 循环体内用
debug,启停/异常/关键结果用info及以上。日志栏默认只看 INFO 及以上,高频 DEBUG 不会刷屏。 - 别用
print(),宿主界面上看不到。 - 存储路径、密钥、用户隐私数据不要写进日志。
对外接口设计约定
宿主不限制你怎么设计方法,但遵守这几点能省掉大部分联调问题:
- 方法名用小写蛇形(
get_devices),风格在模块内保持一致。 - 参数与返回值只用 JSON 可序列化类型,复杂对象先转
dict。 - 不要吞异常。直接抛,调用方会拿到明确错误;前端收到
ok=false与错误描述。 - 长任务立即返回(比如返回任务 ID),后台线程执行,用事件或卡片推进度。
- 查询类方法不要有副作用;写操作尽量可重复执行。
- 在模块
description或页面里列出你注册的方法名与参数,方便别人接入。