纯信号 · 事件广播
独立式节点的典型模式——自行管理生命周期,不开放接口,只向外部广播事件。KnotHub 通过注册表发现它,其他程序订阅它的信号。
真实节点:ClassIsland
模式
ClassIsland ──▶ [event=OnClass] ──────▶ 订阅方 A(上课提醒)
ClassIsland ──▶ [event=OnBreakingTime] ─▶ 订阅方 B(下课播报)
ClassIsland ──▶ [event=OnAfterSchool] ──▶ 订阅方 C(放学通知)
同一个 signalID 广播不同事件,verification 字段让订阅方精确匹配。
注册表
独立式节点不通过 Plugins/ 目录被发现——安装时写入注册表:
HKCU\Software\KnotLink\StandaloneNodes
└── 0x00000031 = "C:\Program Files\ClassIsland"
安装目录根目录下放置两份清单:
C:\Program Files\ClassIsland\
├── ClassIsland.exe
├── standalone_manifest.json
├── FuncList.json
└── ...
安装脚本示例:
New-Item -Path "HKCU:\Software\KnotLink\StandaloneNodes" -Force | Out-Null
Set-ItemProperty -Path "HKCU:\Software\KnotLink\StandaloneNodes" `
-Name "0x00000031" -Value "C:\Program Files\ClassIsland"
清单
standalone_manifest.json:
{
"app_id": "0x00000031",
"app_name": "ClassIsland",
"author": "信",
"version": "v1.0.0",
"description": "课程信息与桌面通知服务",
"download_url": "https://github.com/hxh230802/ClassIsland/releases/latest"
}
FuncList.json — 信号为主,接口为辅:
"signal": {
"OnClass": {
"appID": "0x00000031",
"signalID": "0x00000011",
"description": "上课事件",
"returns": {
"event": {
"description": "事件名",
"verification": "OnClass"
}
}
},
"OnBreakingTime": {
"appID": "0x00000031",
"signalID": "0x00000011",
"description": "下课事件",
"returns": {
"event": {
"description": "事件名",
"verification": "OnBreakingTime"
}
}
},
"OnAfterSchool": {
"appID": "0x00000031",
"signalID": "0x00000011",
"description": "放学事件",
"returns": {
"event": { "description": "事件名", "verification": "OnAfterSchool" },
"time": { "description": "时间" }
}
}
}
signal.returns是对象格式,与openSocket.returns的数组格式不同。
通信代码
from knotlink import SignalSender, KLKVMap
import time
APPID = "0x00000031"
SIGNAL_ID = "0x00000011"
sender = SignalSender(APPID, SIGNAL_ID)
def on_break_time():
"""下课了——广播事件"""
kv = KLKVMap()
kv["event"] = "OnBreakingTime"
sender.emitt(kv.serialize())
def on_class_start():
"""上课了"""
kv = KLKVMap()
kv["event"] = "OnClass"
sender.emitt(kv.serialize())
def on_after_school():
"""放学了"""
kv = KLKVMap()
kv["event"] = "OnAfterSchool"
kv["time"] = time.strftime("%Y-%m-%d %H:%M:%S")
sender.emitt(kv.serialize())
不设置回调、不 return 响应——纯广播,不需要 OpenSocketResponser。
关键点
- 独立式用
standalone_manifest.json— 文件名决定类型,用app_name(不是plugin_name) - 注册表是发现入口 —
HKCU\Software\KnotLink\StandaloneNodes,值名 = app_id,值 = 安装路径 - signal.returns 是对象格式 —
{"event": {"description": "...", "verification": "OnClass"}},跟 openSocket 的数组格式不一样 - verification 用于信号鉴别 — 同一个 signalID 发多种事件,订阅方靠 verification 值精确匹配
- 也可同时开放接口 — ClassIsland 还有
ClassService供查询课程,信号和接口不互斥