@yunzai-ng/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +51 -0
- package/dist/adapter/accounts.d.ts +174 -0
- package/dist/adapter/accounts.d.ts.map +1 -0
- package/dist/adapter/accounts.js +653 -0
- package/dist/adapter/accounts.js.map +1 -0
- package/dist/adapter/bots.d.ts +142 -0
- package/dist/adapter/bots.d.ts.map +1 -0
- package/dist/adapter/bots.js +454 -0
- package/dist/adapter/bots.js.map +1 -0
- package/dist/adapter/host.d.ts +114 -0
- package/dist/adapter/host.d.ts.map +1 -0
- package/dist/adapter/host.js +90 -0
- package/dist/adapter/host.js.map +1 -0
- package/dist/adapter/login.d.ts +174 -0
- package/dist/adapter/login.d.ts.map +1 -0
- package/dist/adapter/login.js +345 -0
- package/dist/adapter/login.js.map +1 -0
- package/dist/adapter/registry.d.ts +102 -0
- package/dist/adapter/registry.d.ts.map +1 -0
- package/dist/adapter/registry.js +150 -0
- package/dist/adapter/registry.js.map +1 -0
- package/dist/config/core-config.d.ts +151 -0
- package/dist/config/core-config.d.ts.map +1 -0
- package/dist/config/core-config.js +338 -0
- package/dist/config/core-config.js.map +1 -0
- package/dist/config/schema.d.ts +449 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +871 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/store.d.ts +184 -0
- package/dist/config/store.d.ts.map +1 -0
- package/dist/config/store.js +428 -0
- package/dist/config/store.js.map +1 -0
- package/dist/config/yaml.d.ts +23 -0
- package/dist/config/yaml.d.ts.map +1 -0
- package/dist/config/yaml.js +108 -0
- package/dist/config/yaml.js.map +1 -0
- package/dist/http/client.d.ts +82 -0
- package/dist/http/client.d.ts.map +1 -0
- package/dist/http/client.js +658 -0
- package/dist/http/client.js.map +1 -0
- package/dist/index.d.ts +77 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +94 -0
- package/dist/index.js.map +1 -0
- package/dist/kernel/app.d.ts +244 -0
- package/dist/kernel/app.d.ts.map +1 -0
- package/dist/kernel/app.js +654 -0
- package/dist/kernel/app.js.map +1 -0
- package/dist/kernel/kv-sink.d.ts +34 -0
- package/dist/kernel/kv-sink.d.ts.map +1 -0
- package/dist/kernel/kv-sink.js +25 -0
- package/dist/kernel/kv-sink.js.map +1 -0
- package/dist/kernel/policy.d.ts +77 -0
- package/dist/kernel/policy.d.ts.map +1 -0
- package/dist/kernel/policy.js +99 -0
- package/dist/kernel/policy.js.map +1 -0
- package/dist/kernel/runtime.d.ts +117 -0
- package/dist/kernel/runtime.d.ts.map +1 -0
- package/dist/kernel/runtime.js +197 -0
- package/dist/kernel/runtime.js.map +1 -0
- package/dist/kernel/sql-sink.d.ts +36 -0
- package/dist/kernel/sql-sink.d.ts.map +1 -0
- package/dist/kernel/sql-sink.js +114 -0
- package/dist/kernel/sql-sink.js.map +1 -0
- package/dist/logger/format.d.ts +67 -0
- package/dist/logger/format.d.ts.map +1 -0
- package/dist/logger/format.js +218 -0
- package/dist/logger/format.js.map +1 -0
- package/dist/logger/index.d.ts +97 -0
- package/dist/logger/index.d.ts.map +1 -0
- package/dist/logger/index.js +363 -0
- package/dist/logger/index.js.map +1 -0
- package/dist/logger/rotate.d.ts +47 -0
- package/dist/logger/rotate.d.ts.map +1 -0
- package/dist/logger/rotate.js +242 -0
- package/dist/logger/rotate.js.map +1 -0
- package/dist/message/segment.d.ts +255 -0
- package/dist/message/segment.d.ts.map +1 -0
- package/dist/message/segment.js +510 -0
- package/dist/message/segment.js.map +1 -0
- package/dist/message/split.d.ts +34 -0
- package/dist/message/split.d.ts.map +1 -0
- package/dist/message/split.js +79 -0
- package/dist/message/split.js.map +1 -0
- package/dist/message/target.d.ts +29 -0
- package/dist/message/target.d.ts.map +1 -0
- package/dist/message/target.js +34 -0
- package/dist/message/target.js.map +1 -0
- package/dist/pipeline/cooldown.d.ts +84 -0
- package/dist/pipeline/cooldown.d.ts.map +1 -0
- package/dist/pipeline/cooldown.js +94 -0
- package/dist/pipeline/cooldown.js.map +1 -0
- package/dist/pipeline/dispatch.d.ts +98 -0
- package/dist/pipeline/dispatch.d.ts.map +1 -0
- package/dist/pipeline/dispatch.js +323 -0
- package/dist/pipeline/dispatch.js.map +1 -0
- package/dist/pipeline/event.d.ts +130 -0
- package/dist/pipeline/event.d.ts.map +1 -0
- package/dist/pipeline/event.js +538 -0
- package/dist/pipeline/event.js.map +1 -0
- package/dist/pipeline/middleware.d.ts +63 -0
- package/dist/pipeline/middleware.d.ts.map +1 -0
- package/dist/pipeline/middleware.js +174 -0
- package/dist/pipeline/middleware.js.map +1 -0
- package/dist/pipeline/prompt.d.ts +80 -0
- package/dist/pipeline/prompt.d.ts.map +1 -0
- package/dist/pipeline/prompt.js +155 -0
- package/dist/pipeline/prompt.js.map +1 -0
- package/dist/pipeline/router.d.ts +98 -0
- package/dist/pipeline/router.d.ts.map +1 -0
- package/dist/pipeline/router.js +489 -0
- package/dist/pipeline/router.js.map +1 -0
- package/dist/platform/detect.d.ts +24 -0
- package/dist/platform/detect.d.ts.map +1 -0
- package/dist/platform/detect.js +178 -0
- package/dist/platform/detect.js.map +1 -0
- package/dist/platform/paths.d.ts +38 -0
- package/dist/platform/paths.d.ts.map +1 -0
- package/dist/platform/paths.js +129 -0
- package/dist/platform/paths.js.map +1 -0
- package/dist/platform/system.d.ts +71 -0
- package/dist/platform/system.d.ts.map +1 -0
- package/dist/platform/system.js +242 -0
- package/dist/platform/system.js.map +1 -0
- package/dist/plugin/context.d.ts +92 -0
- package/dist/plugin/context.d.ts.map +1 -0
- package/dist/plugin/context.js +573 -0
- package/dist/plugin/context.js.map +1 -0
- package/dist/plugin/define.d.ts +92 -0
- package/dist/plugin/define.d.ts.map +1 -0
- package/dist/plugin/define.js +82 -0
- package/dist/plugin/define.js.map +1 -0
- package/dist/plugin/discover.d.ts +106 -0
- package/dist/plugin/discover.d.ts.map +1 -0
- package/dist/plugin/discover.js +254 -0
- package/dist/plugin/discover.js.map +1 -0
- package/dist/plugin/events.d.ts +109 -0
- package/dist/plugin/events.d.ts.map +1 -0
- package/dist/plugin/events.js +209 -0
- package/dist/plugin/events.js.map +1 -0
- package/dist/plugin/hooks.d.ts +266 -0
- package/dist/plugin/hooks.d.ts.map +1 -0
- package/dist/plugin/hooks.js +84 -0
- package/dist/plugin/hooks.js.map +1 -0
- package/dist/plugin/host.d.ts +160 -0
- package/dist/plugin/host.d.ts.map +1 -0
- package/dist/plugin/host.js +546 -0
- package/dist/plugin/host.js.map +1 -0
- package/dist/plugin/market.d.ts +264 -0
- package/dist/plugin/market.d.ts.map +1 -0
- package/dist/plugin/market.js +700 -0
- package/dist/plugin/market.js.map +1 -0
- package/dist/plugin/services.d.ts +116 -0
- package/dist/plugin/services.d.ts.map +1 -0
- package/dist/plugin/services.js +213 -0
- package/dist/plugin/services.js.map +1 -0
- package/dist/plugin/tar.d.ts +65 -0
- package/dist/plugin/tar.d.ts.map +1 -0
- package/dist/plugin/tar.js +277 -0
- package/dist/plugin/tar.js.map +1 -0
- package/dist/render/registry.d.ts +127 -0
- package/dist/render/registry.d.ts.map +1 -0
- package/dist/render/registry.js +306 -0
- package/dist/render/registry.js.map +1 -0
- package/dist/scheduler/index.d.ts +67 -0
- package/dist/scheduler/index.d.ts.map +1 -0
- package/dist/scheduler/index.js +279 -0
- package/dist/scheduler/index.js.map +1 -0
- package/dist/server/api.d.ts +179 -0
- package/dist/server/api.d.ts.map +1 -0
- package/dist/server/api.js +602 -0
- package/dist/server/api.js.map +1 -0
- package/dist/server/auth.d.ts +83 -0
- package/dist/server/auth.d.ts.map +1 -0
- package/dist/server/auth.js +178 -0
- package/dist/server/auth.js.map +1 -0
- package/dist/server/browse.d.ts +60 -0
- package/dist/server/browse.d.ts.map +1 -0
- package/dist/server/browse.js +187 -0
- package/dist/server/browse.js.map +1 -0
- package/dist/server/files.d.ts +27 -0
- package/dist/server/files.d.ts.map +1 -0
- package/dist/server/files.js +76 -0
- package/dist/server/files.js.map +1 -0
- package/dist/server/index.d.ts +189 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +1123 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/table.d.ts +105 -0
- package/dist/server/table.d.ts.map +1 -0
- package/dist/server/table.js +289 -0
- package/dist/server/table.js.map +1 -0
- package/dist/store/index.d.ts +50 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +120 -0
- package/dist/store/index.js.map +1 -0
- package/dist/store/json.d.ts +73 -0
- package/dist/store/json.d.ts.map +1 -0
- package/dist/store/json.js +174 -0
- package/dist/store/json.js.map +1 -0
- package/dist/store/kv.d.ts +126 -0
- package/dist/store/kv.d.ts.map +1 -0
- package/dist/store/kv.js +232 -0
- package/dist/store/kv.js.map +1 -0
- package/dist/store/level.d.ts +103 -0
- package/dist/store/level.d.ts.map +1 -0
- package/dist/store/level.js +119 -0
- package/dist/store/level.js.map +1 -0
- package/dist/store/memory.d.ts +61 -0
- package/dist/store/memory.d.ts.map +1 -0
- package/dist/store/memory.js +94 -0
- package/dist/store/memory.js.map +1 -0
- package/dist/store/sql.d.ts +142 -0
- package/dist/store/sql.d.ts.map +1 -0
- package/dist/store/sql.js +246 -0
- package/dist/store/sql.js.map +1 -0
- package/dist/testing/fake.d.ts +109 -0
- package/dist/testing/fake.d.ts.map +1 -0
- package/dist/testing/fake.js +196 -0
- package/dist/testing/fake.js.map +1 -0
- package/dist/testing/index.d.ts +16 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +16 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/mock-adapter.d.ts +205 -0
- package/dist/testing/mock-adapter.d.ts.map +1 -0
- package/dist/testing/mock-adapter.js +309 -0
- package/dist/testing/mock-adapter.js.map +1 -0
- package/dist/util/deep.d.ts +108 -0
- package/dist/util/deep.d.ts.map +1 -0
- package/dist/util/deep.js +275 -0
- package/dist/util/deep.js.map +1 -0
- package/dist/util/defer.d.ts +107 -0
- package/dist/util/defer.d.ts.map +1 -0
- package/dist/util/defer.js +163 -0
- package/dist/util/defer.js.map +1 -0
- package/dist/util/dispose.d.ts +88 -0
- package/dist/util/dispose.d.ts.map +1 -0
- package/dist/util/dispose.js +143 -0
- package/dist/util/dispose.js.map +1 -0
- package/dist/util/duration.d.ts +28 -0
- package/dist/util/duration.d.ts.map +1 -0
- package/dist/util/duration.js +77 -0
- package/dist/util/duration.js.map +1 -0
- package/dist/util/fs.d.ts +110 -0
- package/dist/util/fs.d.ts.map +1 -0
- package/dist/util/fs.js +269 -0
- package/dist/util/fs.js.map +1 -0
- package/dist/util/id.d.ts +49 -0
- package/dist/util/id.d.ts.map +1 -0
- package/dist/util/id.js +87 -0
- package/dist/util/id.js.map +1 -0
- package/dist/util/lru.d.ts +74 -0
- package/dist/util/lru.d.ts.map +1 -0
- package/dist/util/lru.js +156 -0
- package/dist/util/lru.js.map +1 -0
- package/dist/util/queue.d.ts +64 -0
- package/dist/util/queue.d.ts.map +1 -0
- package/dist/util/queue.js +147 -0
- package/dist/util/queue.js.map +1 -0
- package/dist/util/text.d.ts +86 -0
- package/dist/util/text.d.ts.map +1 -0
- package/dist/util/text.js +182 -0
- package/dist/util/text.js.map +1 -0
- package/package.json +44 -0
- package/src/adapter/accounts.ts +758 -0
- package/src/adapter/bots.ts +582 -0
- package/src/adapter/host.ts +224 -0
- package/src/adapter/login.ts +481 -0
- package/src/adapter/registry.ts +202 -0
- package/src/config/core-config.test.ts +60 -0
- package/src/config/core-config.ts +401 -0
- package/src/config/schema.test.ts +179 -0
- package/src/config/schema.ts +1036 -0
- package/src/config/store.test.ts +245 -0
- package/src/config/store.ts +506 -0
- package/src/config/yaml.ts +119 -0
- package/src/http/client.test.ts +568 -0
- package/src/http/client.ts +777 -0
- package/src/index.ts +106 -0
- package/src/kernel/app.test.ts +267 -0
- package/src/kernel/app.ts +843 -0
- package/src/kernel/kv-sink.ts +58 -0
- package/src/kernel/policy.ts +120 -0
- package/src/kernel/runtime.test.ts +542 -0
- package/src/kernel/runtime.ts +307 -0
- package/src/kernel/sql-sink.ts +154 -0
- package/src/logger/format.ts +259 -0
- package/src/logger/index.ts +427 -0
- package/src/logger/rotate.ts +265 -0
- package/src/message/segment.test.ts +335 -0
- package/src/message/segment.ts +569 -0
- package/src/message/split.ts +97 -0
- package/src/message/target.ts +48 -0
- package/src/pipeline/cooldown.ts +136 -0
- package/src/pipeline/dispatch.ts +419 -0
- package/src/pipeline/event.ts +735 -0
- package/src/pipeline/middleware.test.ts +426 -0
- package/src/pipeline/middleware.ts +199 -0
- package/src/pipeline/prompt.ts +212 -0
- package/src/pipeline/router.test.ts +432 -0
- package/src/pipeline/router.ts +575 -0
- package/src/platform/detect.ts +178 -0
- package/src/platform/paths.ts +147 -0
- package/src/platform/system.test.ts +102 -0
- package/src/platform/system.ts +289 -0
- package/src/plugin/context.test.ts +459 -0
- package/src/plugin/context.ts +757 -0
- package/src/plugin/define.test.ts +120 -0
- package/src/plugin/define.ts +142 -0
- package/src/plugin/discover.test.ts +253 -0
- package/src/plugin/discover.ts +353 -0
- package/src/plugin/events.test.ts +162 -0
- package/src/plugin/events.ts +266 -0
- package/src/plugin/hooks.ts +373 -0
- package/src/plugin/host.test.ts +696 -0
- package/src/plugin/host.ts +738 -0
- package/src/plugin/market.test.ts +781 -0
- package/src/plugin/market.ts +870 -0
- package/src/plugin/services.test.ts +135 -0
- package/src/plugin/services.ts +261 -0
- package/src/plugin/tar.test.ts +158 -0
- package/src/plugin/tar.ts +309 -0
- package/src/render/registry.test.ts +127 -0
- package/src/render/registry.ts +439 -0
- package/src/scheduler/index.ts +357 -0
- package/src/server/api.test.ts +802 -0
- package/src/server/api.ts +869 -0
- package/src/server/auth.ts +201 -0
- package/src/server/browse.test.ts +193 -0
- package/src/server/browse.ts +240 -0
- package/src/server/files.ts +97 -0
- package/src/server/index.test.ts +566 -0
- package/src/server/index.ts +1386 -0
- package/src/server/table.ts +351 -0
- package/src/store/index.ts +156 -0
- package/src/store/json.ts +198 -0
- package/src/store/kv.test.ts +307 -0
- package/src/store/kv.ts +256 -0
- package/src/store/level.ts +167 -0
- package/src/store/memory.ts +109 -0
- package/src/store/sql.test.ts +204 -0
- package/src/store/sql.ts +324 -0
- package/src/testing/fake.ts +297 -0
- package/src/testing/index.ts +15 -0
- package/src/testing/mock-adapter.ts +588 -0
- package/src/util/deep.ts +272 -0
- package/src/util/defer.ts +211 -0
- package/src/util/dispose.ts +169 -0
- package/src/util/duration.ts +82 -0
- package/src/util/fs.ts +279 -0
- package/src/util/id.ts +94 -0
- package/src/util/lru.ts +185 -0
- package/src/util/queue.ts +167 -0
- package/src/util/text.ts +189 -0
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 模块职责:装配运行期子系统 —— 消息管线、调度器、渲染注册表、适配器与账号
|
|
3
|
+
* 依赖方向:依赖 pipeline / scheduler / render / adapter 各层与内核基础设施;
|
|
4
|
+
* **不依赖任何插件**,亦不被上述任何一层反向 import(由 scripts/check-layering.mjs 守卫)
|
|
5
|
+
* 生命周期:`createApp()` 中调用一次,且在 `new App(...)` **之前**;回收动作经 `own()` 移交 `App.stop()`
|
|
6
|
+
* 注意事项:从 `kernel/app.ts` 拆出来是为了让那边只描述生命周期 —— 子系统之间的装配有十余条,
|
|
7
|
+
* 混在 `createApp` 里会把「启动顺序」这条主线盖掉。附带收益是可单独测试:`RuntimeDeps`
|
|
8
|
+
* 是一组窄依赖,不必先造一个真的 `App`。四条不可改的约定:
|
|
9
|
+
*
|
|
10
|
+
* **必须早于 `new App(...)`。** 顺序反了,从 App 构造完到子系统装配完之间有一段空窗,
|
|
11
|
+
* `AppView.bots` 在那期间给出的是空占位注册表 —— 视图虽是 getter,窗口期内每次读取
|
|
12
|
+
* 都是错的。
|
|
13
|
+
*
|
|
14
|
+
* **接缝字段是「替换」而非「注入」。** `hooks` 与 `subsystems` 是可变对象,插件上下文每次
|
|
15
|
+
* 使用时实时读取,故此处直接改写字段即可,不必通知任何一方。
|
|
16
|
+
*
|
|
17
|
+
* **配置一律取 getter 或取值函数,不缓存快照。** 面板改了 `message.splitLength` 应当自下
|
|
18
|
+
* 一条消息即生效。唯一的例外是 `message.concurrency` —— 信号量容量在创建时固定,这一点
|
|
19
|
+
* 已写进它的配置说明。
|
|
20
|
+
*/
|
|
21
|
+
import type { Disposer, Logger } from "@yunzai-ng/types"
|
|
22
|
+
import { AccountManager } from "../adapter/accounts.js"
|
|
23
|
+
import { BotRegistry, type SendPolicyView } from "../adapter/bots.js"
|
|
24
|
+
import { createAdapterHostFactory } from "../adapter/host.js"
|
|
25
|
+
import { LoginManager } from "../adapter/login.js"
|
|
26
|
+
import { AdapterRegistry } from "../adapter/registry.js"
|
|
27
|
+
import type { CoreConfigHandle } from "../config/core-config.js"
|
|
28
|
+
import { CooldownStore } from "../pipeline/cooldown.js"
|
|
29
|
+
import { EventDispatcher } from "../pipeline/dispatch.js"
|
|
30
|
+
import { EventFactory, type PluginRuntimeView } from "../pipeline/event.js"
|
|
31
|
+
import { MiddlewarePipeline } from "../pipeline/middleware.js"
|
|
32
|
+
import { PromptRegistry } from "../pipeline/prompt.js"
|
|
33
|
+
import { CommandRouter } from "../pipeline/router.js"
|
|
34
|
+
import type { CoreEventBus } from "../plugin/events.js"
|
|
35
|
+
import type { KernelHooks } from "../plugin/hooks.js"
|
|
36
|
+
import { RenderRegistry, type RenderPolicy } from "../render/registry.js"
|
|
37
|
+
import { Scheduler } from "../scheduler/index.js"
|
|
38
|
+
import type { KvStore } from "../store/index.js"
|
|
39
|
+
import { parseDuration } from "../util/duration.js"
|
|
40
|
+
import type { KernelSubsystems } from "./app.js"
|
|
41
|
+
import type { KernelPolicy } from "./policy.js"
|
|
42
|
+
|
|
43
|
+
/** 适配器数据的 KV 命名空间名 */
|
|
44
|
+
const KV_ADAPTER = "adapter"
|
|
45
|
+
|
|
46
|
+
/** 账号记录的 KV 命名空间名 */
|
|
47
|
+
const KV_ACCOUNTS = "accounts"
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 发送超时读不出来时的兜底毫秒
|
|
51
|
+
*
|
|
52
|
+
* 与 `message.sendTimeout` 的 schema 默认值 `"30s"` 对应。schema 会在加载时
|
|
53
|
+
* 校验时长格式,所以这个兜底实际上走不到;留着是因为"发送永不超时"的后果比
|
|
54
|
+
* 一个偏差几秒的超时严重得多 —— 在 `sequential` 模式下,一次永不结束的发送
|
|
55
|
+
* 会把那个会话的队列永久堵死。
|
|
56
|
+
*/
|
|
57
|
+
const FALLBACK_SEND_TIMEOUT = 30_000
|
|
58
|
+
|
|
59
|
+
/** 装配运行期子系统所需的依赖 */
|
|
60
|
+
export interface RuntimeDeps {
|
|
61
|
+
/** 根日志器;各子系统自行派生 child */
|
|
62
|
+
readonly logger: Logger
|
|
63
|
+
/** 内核配置句柄 */
|
|
64
|
+
readonly config: CoreConfigHandle
|
|
65
|
+
/** KV 存储 */
|
|
66
|
+
readonly kv: KvStore
|
|
67
|
+
/** 内核事件总线 */
|
|
68
|
+
readonly events: CoreEventBus
|
|
69
|
+
/** 内核策略(同时充当三层的策略视图,见 `installRuntime` 的注释) */
|
|
70
|
+
readonly policy: KernelPolicy
|
|
71
|
+
/** 子系统接缝;本函数会替换其中五个字段 */
|
|
72
|
+
readonly hooks: KernelHooks
|
|
73
|
+
/** 可后填的子系统视图;本函数会替换全部四个字段 */
|
|
74
|
+
readonly subsystems: KernelSubsystems
|
|
75
|
+
/**
|
|
76
|
+
* 按插件名取运行时上下文
|
|
77
|
+
*
|
|
78
|
+
* 由插件宿主提供(`PluginHost.runtime`)。分发器靠它把 `e.render()` 的模板根、
|
|
79
|
+
* `e.prompt()` 的卸载信号绑到发起命令的那个插件上。
|
|
80
|
+
* @param name 插件名
|
|
81
|
+
* @returns 插件运行时视图;未加载或已卸载时 undefined
|
|
82
|
+
*/
|
|
83
|
+
readonly plugins: (name: string) => PluginRuntimeView | undefined
|
|
84
|
+
/**
|
|
85
|
+
* 登记一个需要在停机时回收的动作
|
|
86
|
+
*
|
|
87
|
+
* 回收按登记的**逆序**执行,见 `kernel/app.ts` 的 `own()`。
|
|
88
|
+
* @param dispose 回收函数
|
|
89
|
+
*/
|
|
90
|
+
readonly own: (dispose: Disposer) => void
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* 装配好的运行期子系统
|
|
95
|
+
*
|
|
96
|
+
* 暴露的是**具体实现**而不是窄视图:WebUI(阶段四)要做账号增删改查、要看
|
|
97
|
+
* 登录会话快照、要列渲染器、要读分发器的积压计数,这些都在 `AppView` 的
|
|
98
|
+
* 只读视图之外。`App` 持有这一份,WebUI 从 `App` 拿。
|
|
99
|
+
*/
|
|
100
|
+
export interface RuntimeParts {
|
|
101
|
+
/** `prompt` 等待者登记表 */
|
|
102
|
+
readonly prompts: PromptRegistry
|
|
103
|
+
/** 事件工厂 */
|
|
104
|
+
readonly factory: EventFactory
|
|
105
|
+
/** 中间件管线 */
|
|
106
|
+
readonly middlewares: MiddlewarePipeline
|
|
107
|
+
/** 命令路由 */
|
|
108
|
+
readonly router: CommandRouter
|
|
109
|
+
/** 冷却存储 */
|
|
110
|
+
readonly cooldown: CooldownStore
|
|
111
|
+
/** 事件分发器(适配器唯一的入口) */
|
|
112
|
+
readonly dispatcher: EventDispatcher
|
|
113
|
+
/** 定时任务调度器 */
|
|
114
|
+
readonly scheduler: Scheduler
|
|
115
|
+
/** 渲染注册表 */
|
|
116
|
+
readonly renderers: RenderRegistry
|
|
117
|
+
/** 适配器注册表 */
|
|
118
|
+
readonly adapters: AdapterRegistry
|
|
119
|
+
/** 在线 Bot 注册表 */
|
|
120
|
+
readonly bots: BotRegistry
|
|
121
|
+
/** 账号管理器 */
|
|
122
|
+
readonly accounts: AccountManager
|
|
123
|
+
/** 登录会话管理器 */
|
|
124
|
+
readonly logins: LoginManager
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* 取当前渲染策略
|
|
129
|
+
*
|
|
130
|
+
* 超时解析不出来时给 0:`RenderRegistry.render()` 对非正值有自己的兜底
|
|
131
|
+
* (60 秒),把那个数字再抄一遍只会多一处需要同步维护的地方。
|
|
132
|
+
* @param config 内核配置句柄
|
|
133
|
+
* @returns 渲染策略
|
|
134
|
+
*/
|
|
135
|
+
function renderPolicyOf(config: CoreConfigHandle): RenderPolicy {
|
|
136
|
+
const r = config.get().render
|
|
137
|
+
return {
|
|
138
|
+
default: r.default,
|
|
139
|
+
timeout: parseDuration(r.timeout, 0),
|
|
140
|
+
retry: r.retry,
|
|
141
|
+
quality: r.quality,
|
|
142
|
+
scale: r.scale
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* 造一份"活的"发送策略视图
|
|
148
|
+
*
|
|
149
|
+
* 三个字段都是 getter:`BotFacade` 在**每次发送时**读它们(见 adapter/bots.ts),
|
|
150
|
+
* 所以在面板上把切分长度从 3000 改成 1000,下一条消息就按 1000 切,
|
|
151
|
+
* 不需要重连账号。缓存成快照的话就得重连才生效。
|
|
152
|
+
* @param config 内核配置句柄
|
|
153
|
+
* @returns 发送策略视图
|
|
154
|
+
*/
|
|
155
|
+
function sendPolicyOf(config: CoreConfigHandle): SendPolicyView {
|
|
156
|
+
return {
|
|
157
|
+
get splitLength(): number {
|
|
158
|
+
return config.get().message.splitLength
|
|
159
|
+
},
|
|
160
|
+
get sendTimeout(): number {
|
|
161
|
+
return parseDuration(config.get().message.sendTimeout, FALLBACK_SEND_TIMEOUT)
|
|
162
|
+
},
|
|
163
|
+
get sequential(): boolean {
|
|
164
|
+
return config.get().message.sequential
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* 装配全部运行期子系统,并把它们填进内核接缝
|
|
171
|
+
*
|
|
172
|
+
* 构造顺序按依赖来:管线(内层)→ 调度器与渲染(旁挂)→ 适配器与账号(外层,
|
|
173
|
+
* 事件从这里进来)。`KernelPolicy` 会被同时当成 `DispatchPolicyView`、
|
|
174
|
+
* `EventPolicyView`、`PolicyView` 传下去 —— 它结构上满足三者,多写三个适配器
|
|
175
|
+
* 对象只会让"这几个视图必须对得上"这件事变得不明显。
|
|
176
|
+
* @param deps 依赖
|
|
177
|
+
* @returns 装配好的子系统
|
|
178
|
+
*/
|
|
179
|
+
export function installRuntime(deps: RuntimeDeps): RuntimeParts {
|
|
180
|
+
const { logger, config, kv, events, policy, hooks, subsystems } = deps
|
|
181
|
+
const log = logger.child({ scope: "runtime" })
|
|
182
|
+
|
|
183
|
+
// ── 1. 消息管线 ───────────────────────────────────────────────────────
|
|
184
|
+
const prompts = new PromptRegistry()
|
|
185
|
+
const factory = new EventFactory({ logger, policy, prompts })
|
|
186
|
+
const middlewares = new MiddlewarePipeline(logger)
|
|
187
|
+
const router = new CommandRouter({ logger })
|
|
188
|
+
const cooldown = new CooldownStore()
|
|
189
|
+
const dispatcher = new EventDispatcher({
|
|
190
|
+
logger,
|
|
191
|
+
policy,
|
|
192
|
+
events,
|
|
193
|
+
factory,
|
|
194
|
+
middlewares,
|
|
195
|
+
router,
|
|
196
|
+
cooldown,
|
|
197
|
+
prompts,
|
|
198
|
+
plugins: deps.plugins,
|
|
199
|
+
// 只读一次:信号量的容量在构造时定下,见文件头第 4 条
|
|
200
|
+
concurrency: config.get().message.concurrency
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
// ── 2. 调度器与渲染 ───────────────────────────────────────────────────
|
|
204
|
+
const scheduler = new Scheduler({ logger })
|
|
205
|
+
// onDone 在此处接线而非由注册表自己认识总线:注册表对渲染实现零认知,
|
|
206
|
+
// 认识事件总线就等于认识插件系统(见 render/registry.ts 的构造参数注释)
|
|
207
|
+
const renderers = new RenderRegistry({
|
|
208
|
+
logger,
|
|
209
|
+
policy: () => renderPolicyOf(config),
|
|
210
|
+
onDone: info => events.emitDetached("render/done", info)
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
// ── 3. 适配器与账号 ───────────────────────────────────────────────────
|
|
214
|
+
const adapters = new AdapterRegistry({ logger })
|
|
215
|
+
const bots = new BotRegistry({ logger })
|
|
216
|
+
const createHost = createAdapterHostFactory({
|
|
217
|
+
logger,
|
|
218
|
+
kv: kv.namespace(KV_ADAPTER),
|
|
219
|
+
policy,
|
|
220
|
+
server: () => hooks.server,
|
|
221
|
+
// 不 await:适配器是在 socket 回调里调 dispatch 的,一条消息处理多久
|
|
222
|
+
// 都不该把下一条报文的读取堵住。`submit()` 契约上永不抛出,所以也不需要
|
|
223
|
+
// 在这里 catch —— 真出错了它自己会落日志并发 pipeline/error。
|
|
224
|
+
dispatch: (event, bot) => void dispatcher.submit(event, bot)
|
|
225
|
+
})
|
|
226
|
+
const accounts = new AccountManager({
|
|
227
|
+
logger,
|
|
228
|
+
kv: kv.namespace(KV_ACCOUNTS),
|
|
229
|
+
adapters,
|
|
230
|
+
bots,
|
|
231
|
+
createHost,
|
|
232
|
+
events,
|
|
233
|
+
sendPolicy: sendPolicyOf(config)
|
|
234
|
+
})
|
|
235
|
+
const logins = new LoginManager({
|
|
236
|
+
logger,
|
|
237
|
+
adapters,
|
|
238
|
+
createAccount: (adapterId, cfg, label) => accounts.create(adapterId, cfg, label)
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
// ── 4. 填进接缝 ───────────────────────────────────────────────────────
|
|
242
|
+
// 这五个在 app.ts 里原本是 unavailable*() 占位,插件调用它们会拿到一条
|
|
243
|
+
// "该子系统尚未装配"的错误;替换之后已加载的插件立刻看到真实现
|
|
244
|
+
hooks.commands = router
|
|
245
|
+
hooks.middlewares = middlewares
|
|
246
|
+
hooks.tasks = scheduler
|
|
247
|
+
hooks.render = renderers
|
|
248
|
+
hooks.adapters = adapters
|
|
249
|
+
|
|
250
|
+
// hooks.bots.pick 不用动:app.ts 里那个闭包读的是 subsystems.bots,现取现用
|
|
251
|
+
subsystems.adapters = adapters
|
|
252
|
+
subsystems.bots = bots
|
|
253
|
+
subsystems.accounts = accounts
|
|
254
|
+
subsystems.registries = {
|
|
255
|
+
commands: () => router.list(),
|
|
256
|
+
tasks: () => scheduler.list(),
|
|
257
|
+
middlewares: () => middlewares.list()
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// ── 5. 账号上线时机 ───────────────────────────────────────────────────
|
|
261
|
+
// 挂在 app/ready 而不是就地连接:适配器由插件注册,插件全部加载完之前连接
|
|
262
|
+
// 必然因"适配器未注册"白失败一次(见 adapter/accounts.ts 的 load 注释)。
|
|
263
|
+
deps.own(
|
|
264
|
+
events.on("app/ready", async () => {
|
|
265
|
+
// 只 await load():账号列表要在 start() 返回前就位(WebUI 与插件的
|
|
266
|
+
// app/ready 都可能立刻去读它)。而"连上"取决于对端 —— NapCat 没启动时
|
|
267
|
+
// 一次 TCP 连接可能耗时数十秒,使 start() 阻塞于此只会令使用者误判框架已无响应。
|
|
268
|
+
// 连接失败有退避重连兜着,插件想知道上线时机请听 bot/online。
|
|
269
|
+
await accounts.load()
|
|
270
|
+
void accounts.startAll().catch((err: unknown) => {
|
|
271
|
+
log.error("启动账号时出现未预期的错误", err)
|
|
272
|
+
})
|
|
273
|
+
})
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
// ── 6. 停机回收 ───────────────────────────────────────────────────────
|
|
277
|
+
// 登记顺序 = 从内到外,`App.stop()` 逆序执行(见 kernel/app.ts 第 3 步),
|
|
278
|
+
// 于是实际关闭顺序是:账号 → 登录会话 → 管线残留 → 调度器 → 渲染器。
|
|
279
|
+
// 先断账号,此后不再有新事件进管线;渲染器最后关,因为在它之前的每一步
|
|
280
|
+
// 都还可能要出一张图(比如插件在 app/stopping 里发一条告别消息)。
|
|
281
|
+
deps.own(() => renderers.stop())
|
|
282
|
+
deps.own(() => scheduler.stop())
|
|
283
|
+
deps.own(() => {
|
|
284
|
+
// 兜底清扫:正常路径下插件卸载已逐条完整摘除,此处防的是越界注册
|
|
285
|
+
middlewares.clear()
|
|
286
|
+
router.clear()
|
|
287
|
+
prompts.clear()
|
|
288
|
+
cooldown.clear()
|
|
289
|
+
})
|
|
290
|
+
deps.own(() => logins.stop())
|
|
291
|
+
deps.own(() => accounts.stop())
|
|
292
|
+
|
|
293
|
+
return {
|
|
294
|
+
prompts,
|
|
295
|
+
factory,
|
|
296
|
+
middlewares,
|
|
297
|
+
router,
|
|
298
|
+
cooldown,
|
|
299
|
+
dispatcher,
|
|
300
|
+
scheduler,
|
|
301
|
+
renderers,
|
|
302
|
+
adapters,
|
|
303
|
+
bots,
|
|
304
|
+
accounts,
|
|
305
|
+
logins
|
|
306
|
+
}
|
|
307
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 模块职责:把 `store/sql.ts` 的 SQLite 能力接到插件上下文的 `SqlSink` 接缝上
|
|
3
|
+
* 依赖方向:依赖 store/sql、plugin/hooks、类型包;不依赖任何插件
|
|
4
|
+
* 生命周期:应用级单例,`closeAll()` 时关闭全部连接
|
|
5
|
+
* 注意事项:连接的**归属**在这里确定 —— 每个插件的库落在 `<data>/sql/<插件名>/<库名>.db`,
|
|
6
|
+
* 插件卸载时由上下文调用 `close(插件名)` 一次性关掉它开过的所有库。
|
|
7
|
+
* `SqlHandle` 上刻意没有 `close()`:句柄会被插件在模块间传递,
|
|
8
|
+
* 谁都能关就意味着谁都可能在别人还在用时关掉。
|
|
9
|
+
*
|
|
10
|
+
* `open()` 缓存的是**Promise 而不是结果**。两个模块在同一 tick 里
|
|
11
|
+
* `await ctx.sql("gacha")` 是常见写法,缓存结果的话两次都会 miss,
|
|
12
|
+
* 于是同一个文件被打开两次 —— SQLite 允许,但两个连接各有一套
|
|
13
|
+
* 语句缓存和 WAL 视图,写入会互相 SQLITE_BUSY。
|
|
14
|
+
*/
|
|
15
|
+
import { join } from "node:path"
|
|
16
|
+
import type { Logger, SqlHandle } from "@yunzai-ng/types"
|
|
17
|
+
import { SubsystemUnavailableError, type SqlSink } from "../plugin/hooks.js"
|
|
18
|
+
import { openSql, type SqlStore } from "../store/sql.js"
|
|
19
|
+
|
|
20
|
+
/** 库名与插件名的合法形式:不含路径分隔符,避免写到目录外面去 */
|
|
21
|
+
const SAFE_NAME = /^[a-z0-9][a-z0-9._-]*$/i
|
|
22
|
+
|
|
23
|
+
/** 创建 SQL 接缝的参数 */
|
|
24
|
+
export interface SqlSinkOptions {
|
|
25
|
+
/** 存放 `.db` 文件的根目录(绝对路径) */
|
|
26
|
+
dir: string
|
|
27
|
+
/** 日志器 */
|
|
28
|
+
logger: Logger
|
|
29
|
+
/** 是否启用(对应配置 `store.sqlite`) */
|
|
30
|
+
enabled: boolean
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** 带生命周期管理的 SQL 接缝 */
|
|
34
|
+
export interface ManagedSqlSink extends SqlSink {
|
|
35
|
+
/** 当前打开的库数量 */
|
|
36
|
+
readonly size: number
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* 列出已打开的库
|
|
40
|
+
* @returns 形如 `["mhy-game/gacha"]` 的键数组,按字典序
|
|
41
|
+
*/
|
|
42
|
+
list(): string[]
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 关闭全部库
|
|
46
|
+
* @returns 全部关闭后兑现
|
|
47
|
+
*/
|
|
48
|
+
closeAll(): Promise<void>
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 校验一段名字能不能安全地当目录/文件名用
|
|
53
|
+
* @param kind 名字用途,用于报错
|
|
54
|
+
* @param value 待校验的名字
|
|
55
|
+
* @throws 名字非法时
|
|
56
|
+
*/
|
|
57
|
+
function assertSafe(kind: string, value: string): void {
|
|
58
|
+
if (!SAFE_NAME.test(value)) {
|
|
59
|
+
throw new Error(`${kind} ${JSON.stringify(value)} 不合法:需以字母或数字开头,只含字母数字与 . - _`)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* 创建 SQL 接缝
|
|
65
|
+
*
|
|
66
|
+
* 未启用或原生模块缺失时并不在此处报错,而是等到插件确实调用 `open()`:
|
|
67
|
+
* 多数插件完全不使用 SQL,为其在启动期抛错等于将"可选依赖"变为必选。
|
|
68
|
+
* @param opts 参数
|
|
69
|
+
* @returns SQL 接缝
|
|
70
|
+
*/
|
|
71
|
+
export function createSqlSink(opts: SqlSinkOptions): ManagedSqlSink {
|
|
72
|
+
const logger = opts.logger.child({ scope: "sql" })
|
|
73
|
+
/** `插件名/库名` → 打开中或已打开的库 */
|
|
74
|
+
const opened = new Map<string, Promise<SqlStore>>()
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* 关闭一个库并从表中摘除
|
|
78
|
+
* @param key 缓存键
|
|
79
|
+
* @param pending 打开中或已打开的库
|
|
80
|
+
*/
|
|
81
|
+
const shut = async (key: string, pending: Promise<SqlStore>): Promise<void> => {
|
|
82
|
+
opened.delete(key)
|
|
83
|
+
try {
|
|
84
|
+
// 必须 await:若对正在打开的库直接丢弃引用,连接会在无人持有的情况下
|
|
85
|
+
// 泄漏于事件循环中,导致进程无法退出
|
|
86
|
+
const store = await pending
|
|
87
|
+
store.close()
|
|
88
|
+
} catch (err) {
|
|
89
|
+
// 对打开阶段即已失败的库,此处再次抛出并无意义
|
|
90
|
+
logger.debug(`关闭 ${key} 时出错(打开阶段可能就已失败)`, err)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
get size(): number {
|
|
96
|
+
return opened.size
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
list(): string[] {
|
|
100
|
+
return [...opened.keys()].sort()
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
async open(plugin: string, name: string): Promise<SqlHandle> {
|
|
104
|
+
assertSafe("插件名", plugin)
|
|
105
|
+
assertSafe("库名", name)
|
|
106
|
+
|
|
107
|
+
if (!opts.enabled) {
|
|
108
|
+
throw new SubsystemUnavailableError("SQL", "配置项 store.sqlite 为 false,在 WebUI 里开启后重启即可")
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const key = `${plugin}/${name}`
|
|
112
|
+
const cached = opened.get(key)
|
|
113
|
+
if (cached) return (await cached).handle
|
|
114
|
+
|
|
115
|
+
const pending = (async (): Promise<SqlStore> => {
|
|
116
|
+
const file = join(opts.dir, plugin, `${name}.db`)
|
|
117
|
+
const store = await openSql({ file })
|
|
118
|
+
if (!store) {
|
|
119
|
+
throw new SubsystemUnavailableError(
|
|
120
|
+
"SQL",
|
|
121
|
+
"可选依赖 better-sqlite3 不可用(Termux 等环境常编译失败)。" +
|
|
122
|
+
"执行 pnpm rebuild better-sqlite3 重装,或让插件降级用 ctx.kv"
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
logger.debug(`已打开 ${key} → ${store.file}`)
|
|
126
|
+
return store
|
|
127
|
+
})()
|
|
128
|
+
|
|
129
|
+
opened.set(key, pending)
|
|
130
|
+
try {
|
|
131
|
+
return (await pending).handle
|
|
132
|
+
} catch (err) {
|
|
133
|
+
// 失败的 Promise 不留在表里:磁盘满、权限不对这类问题修好之后
|
|
134
|
+
// 插件重载应该能重新打开,而不是一直拿到同一个陈旧的 rejection
|
|
135
|
+
opened.delete(key)
|
|
136
|
+
throw err
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
async close(plugin: string): Promise<void> {
|
|
141
|
+
const prefix = `${plugin}/`
|
|
142
|
+
const jobs: Promise<void>[] = []
|
|
143
|
+
for (const [key, pending] of opened) {
|
|
144
|
+
if (key.startsWith(prefix)) jobs.push(shut(key, pending))
|
|
145
|
+
}
|
|
146
|
+
await Promise.all(jobs)
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
async closeAll(): Promise<void> {
|
|
150
|
+
const jobs = [...opened].map(([key, pending]) => shut(key, pending))
|
|
151
|
+
await Promise.all(jobs)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|