@planet-matrix/mobius-model 0.6.0 → 0.10.1
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/CHANGELOG.md +50 -0
- package/oxlint.config.ts +1 -2
- package/package.json +29 -17
- package/scripts/build.ts +2 -52
- package/src/ai/README.md +1 -0
- package/src/ai/ai.ts +107 -0
- package/src/ai/chat-completion-ai/aihubmix-chat-completion.ts +78 -0
- package/src/ai/chat-completion-ai/chat-completion-ai.ts +270 -0
- package/src/ai/chat-completion-ai/chat-completion.ts +189 -0
- package/src/ai/chat-completion-ai/index.ts +7 -0
- package/src/ai/chat-completion-ai/lingyiwanwu-chat-completion.ts +78 -0
- package/src/ai/chat-completion-ai/ohmygpt-chat-completion.ts +78 -0
- package/src/ai/chat-completion-ai/openai-next-chat-completion.ts +78 -0
- package/src/ai/embedding-ai/embedding-ai.ts +63 -0
- package/src/ai/embedding-ai/embedding.ts +50 -0
- package/src/ai/embedding-ai/index.ts +4 -0
- package/src/ai/embedding-ai/openai-next-embedding.ts +23 -0
- package/src/ai/index.ts +4 -0
- package/src/aio/README.md +100 -0
- package/src/aio/content.ts +141 -0
- package/src/aio/index.ts +3 -0
- package/src/aio/json.ts +127 -0
- package/src/aio/prompt.ts +246 -0
- package/src/basic/README.md +20 -15
- package/src/basic/error.ts +19 -5
- package/src/basic/function.ts +2 -2
- package/src/basic/index.ts +1 -0
- package/src/basic/promise.ts +141 -71
- package/src/basic/schedule.ts +111 -0
- package/src/basic/stream.ts +135 -25
- package/src/credential/README.md +107 -0
- package/src/credential/api-key.ts +158 -0
- package/src/credential/bearer.ts +73 -0
- package/src/credential/index.ts +4 -0
- package/src/credential/json-web-token.ts +96 -0
- package/src/credential/password.ts +170 -0
- package/src/cron/README.md +86 -0
- package/src/cron/cron.ts +87 -0
- package/src/cron/index.ts +1 -0
- package/src/drizzle/README.md +1 -0
- package/src/drizzle/drizzle.ts +1 -0
- package/src/drizzle/helper.ts +47 -0
- package/src/drizzle/index.ts +5 -0
- package/src/drizzle/infer.ts +52 -0
- package/src/drizzle/kysely.ts +8 -0
- package/src/drizzle/pagination.ts +198 -0
- package/src/email/README.md +1 -0
- package/src/email/index.ts +1 -0
- package/src/email/resend.ts +25 -0
- package/src/event/class-event-proxy.ts +5 -6
- package/src/event/common.ts +13 -3
- package/src/event/event-manager.ts +3 -3
- package/src/event/instance-event-proxy.ts +5 -6
- package/src/event/internal.ts +4 -4
- package/src/exception/README.md +28 -19
- package/src/exception/error/error.ts +123 -0
- package/src/exception/error/index.ts +2 -0
- package/src/exception/error/match.ts +38 -0
- package/src/exception/error/must-fix.ts +17 -0
- package/src/exception/index.ts +2 -0
- package/src/file-system/find.ts +53 -0
- package/src/file-system/index.ts +2 -0
- package/src/file-system/path.ts +76 -0
- package/src/file-system/resolve.ts +22 -0
- package/src/form/README.md +25 -0
- package/src/form/index.ts +1 -0
- package/src/form/inputor-controller/base.ts +861 -0
- package/src/form/inputor-controller/boolean.ts +39 -0
- package/src/form/inputor-controller/file.ts +39 -0
- package/src/form/inputor-controller/form.ts +179 -0
- package/src/form/inputor-controller/helper.ts +117 -0
- package/src/form/inputor-controller/index.ts +17 -0
- package/src/form/inputor-controller/multi-select.ts +99 -0
- package/src/form/inputor-controller/number.ts +116 -0
- package/src/form/inputor-controller/select.ts +109 -0
- package/src/form/inputor-controller/text.ts +82 -0
- package/src/http/READMD.md +1 -0
- package/src/http/api/api-core.ts +84 -0
- package/src/http/api/api-handler.ts +79 -0
- package/src/http/api/api-host.ts +47 -0
- package/src/http/api/api-result.ts +56 -0
- package/src/http/api/api-schema.ts +154 -0
- package/src/http/api/api-server.ts +130 -0
- package/src/http/api/api-test.ts +142 -0
- package/src/http/api/api-type.ts +34 -0
- package/src/http/api/api.ts +81 -0
- package/src/http/api/index.ts +11 -0
- package/src/http/api-adapter/api-core-node-http.ts +260 -0
- package/src/http/api-adapter/api-host-node-http.ts +156 -0
- package/src/http/api-adapter/api-result-arktype.ts +294 -0
- package/src/http/api-adapter/api-result-zod.ts +286 -0
- package/src/http/api-adapter/index.ts +5 -0
- package/src/http/bin/gen-api-list/gen-api-list.ts +126 -0
- package/src/http/bin/gen-api-list/index.ts +1 -0
- package/src/http/bin/gen-api-test/gen-api-test.ts +136 -0
- package/src/http/bin/gen-api-test/index.ts +1 -0
- package/src/http/bin/gen-api-type/calc-code.ts +25 -0
- package/src/http/bin/gen-api-type/gen-api-type.ts +127 -0
- package/src/http/bin/gen-api-type/index.ts +2 -0
- package/src/http/bin/index.ts +2 -0
- package/src/http/index.ts +3 -0
- package/src/huawei/README.md +1 -0
- package/src/huawei/index.ts +2 -0
- package/src/huawei/moderation/index.ts +1 -0
- package/src/huawei/moderation/moderation.ts +355 -0
- package/src/huawei/obs/esdk-obs-nodejs.d.ts +87 -0
- package/src/huawei/obs/index.ts +1 -0
- package/src/huawei/obs/obs.ts +42 -0
- package/src/index.ts +21 -2
- package/src/json/README.md +92 -0
- package/src/json/index.ts +1 -0
- package/src/json/repair.ts +18 -0
- package/src/log/logger.ts +15 -4
- package/src/openai/README.md +1 -0
- package/src/openai/index.ts +1 -0
- package/src/openai/openai.ts +509 -0
- package/src/orchestration/README.md +9 -7
- package/src/orchestration/dispatching/dispatcher.ts +83 -0
- package/src/orchestration/dispatching/index.ts +2 -0
- package/src/orchestration/dispatching/selector/base-selector.ts +39 -0
- package/src/orchestration/dispatching/selector/down-count-selector.ts +119 -0
- package/src/orchestration/dispatching/selector/index.ts +2 -0
- package/src/orchestration/index.ts +2 -0
- package/src/orchestration/scheduling/index.ts +2 -0
- package/src/orchestration/scheduling/scheduler.ts +103 -0
- package/src/orchestration/scheduling/task.ts +32 -0
- package/src/random/README.md +8 -7
- package/src/random/base.ts +66 -0
- package/src/random/index.ts +5 -1
- package/src/random/random-boolean.ts +40 -0
- package/src/random/random-integer.ts +60 -0
- package/src/random/random-number.ts +72 -0
- package/src/random/random-string.ts +66 -0
- package/src/request/README.md +108 -0
- package/src/request/fetch/base.ts +108 -0
- package/src/request/fetch/browser.ts +280 -0
- package/src/request/fetch/general.ts +20 -0
- package/src/request/fetch/index.ts +4 -0
- package/src/request/fetch/nodejs.ts +280 -0
- package/src/request/index.ts +2 -0
- package/src/request/request/base.ts +246 -0
- package/src/request/request/general.ts +63 -0
- package/src/request/request/index.ts +3 -0
- package/src/request/request/resource.ts +68 -0
- package/src/result/README.md +4 -0
- package/src/result/controller.ts +58 -0
- package/src/result/either.ts +363 -0
- package/src/result/generator.ts +168 -0
- package/src/result/index.ts +3 -0
- package/src/route/README.md +105 -0
- package/src/route/adapter/browser.ts +122 -0
- package/src/route/adapter/driver.ts +56 -0
- package/src/route/adapter/index.ts +2 -0
- package/src/route/index.ts +3 -0
- package/src/route/router/index.ts +2 -0
- package/src/route/router/route.ts +630 -0
- package/src/route/router/router.ts +1641 -0
- package/src/route/uri/hash.ts +307 -0
- package/src/route/uri/index.ts +7 -0
- package/src/route/uri/pathname.ts +376 -0
- package/src/route/uri/search.ts +412 -0
- package/src/service/README.md +1 -0
- package/src/service/index.ts +1 -0
- package/src/service/service.ts +110 -0
- package/src/socket/README.md +105 -0
- package/src/socket/client/index.ts +2 -0
- package/src/socket/client/socket-unit.ts +658 -0
- package/src/socket/client/socket.ts +203 -0
- package/src/socket/common/index.ts +2 -0
- package/src/socket/common/socket-unit-common.ts +23 -0
- package/src/socket/common/socket-unit-heartbeat.ts +427 -0
- package/src/socket/index.ts +3 -0
- package/src/socket/server/index.ts +3 -0
- package/src/socket/server/server.ts +183 -0
- package/src/socket/server/socket-unit.ts +448 -0
- package/src/socket/server/socket.ts +264 -0
- package/src/storage/table.ts +3 -3
- package/src/timer/expiration/expiration-manager.ts +3 -3
- package/src/timer/expiration/remaining-manager.ts +3 -3
- package/src/tube/README.md +99 -0
- package/src/tube/helper.ts +137 -0
- package/src/tube/index.ts +2 -0
- package/src/tube/tube.ts +880 -0
- package/src/weixin/README.md +1 -0
- package/src/weixin/index.ts +2 -0
- package/src/weixin/official-account/authorization.ts +157 -0
- package/src/weixin/official-account/index.ts +2 -0
- package/src/weixin/official-account/js-api.ts +132 -0
- package/src/weixin/open/index.ts +1 -0
- package/src/weixin/open/oauth2.ts +131 -0
- package/tests/unit/ai/ai.spec.ts +85 -0
- package/tests/unit/aio/content.spec.ts +105 -0
- package/tests/unit/aio/json.spec.ts +146 -0
- package/tests/unit/aio/prompt.spec.ts +111 -0
- package/tests/unit/basic/error.spec.ts +16 -4
- package/tests/unit/basic/promise.spec.ts +158 -50
- package/tests/unit/basic/schedule.spec.ts +74 -0
- package/tests/unit/basic/stream.spec.ts +90 -37
- package/tests/unit/credential/api-key.spec.ts +36 -0
- package/tests/unit/credential/bearer.spec.ts +23 -0
- package/tests/unit/credential/json-web-token.spec.ts +23 -0
- package/tests/unit/credential/password.spec.ts +40 -0
- package/tests/unit/cron/cron.spec.ts +84 -0
- package/tests/unit/event/class-event-proxy.spec.ts +3 -3
- package/tests/unit/event/event-manager.spec.ts +3 -3
- package/tests/unit/event/instance-event-proxy.spec.ts +3 -3
- package/tests/unit/exception/error/error.spec.ts +83 -0
- package/tests/unit/exception/error/match.spec.ts +81 -0
- package/tests/unit/form/inputor-controller/base.spec.ts +458 -0
- package/tests/unit/form/inputor-controller/boolean.spec.ts +30 -0
- package/tests/unit/form/inputor-controller/file.spec.ts +27 -0
- package/tests/unit/form/inputor-controller/form.spec.ts +120 -0
- package/tests/unit/form/inputor-controller/helper.spec.ts +67 -0
- package/tests/unit/form/inputor-controller/multi-select.spec.ts +34 -0
- package/tests/unit/form/inputor-controller/number.spec.ts +36 -0
- package/tests/unit/form/inputor-controller/select.spec.ts +49 -0
- package/tests/unit/form/inputor-controller/text.spec.ts +34 -0
- package/tests/unit/http/api/api-core-host.spec.ts +207 -0
- package/tests/unit/http/api/api-schema.spec.ts +120 -0
- package/tests/unit/http/api/api-server.spec.ts +363 -0
- package/tests/unit/http/api/api-test.spec.ts +117 -0
- package/tests/unit/http/api/api.spec.ts +121 -0
- package/tests/unit/http/api-adapter/node-http.spec.ts +187 -0
- package/tests/unit/identifier/uuid.spec.ts +0 -1
- package/tests/unit/json/repair.spec.ts +11 -0
- package/tests/unit/log/logger.spec.ts +19 -4
- package/tests/unit/openai/openai.spec.ts +64 -0
- package/tests/unit/orchestration/dispatching/dispatcher.spec.ts +41 -0
- package/tests/unit/orchestration/dispatching/selector/down-count-selector.spec.ts +81 -0
- package/tests/unit/orchestration/scheduling/scheduler.spec.ts +103 -0
- package/tests/unit/random/base.spec.ts +58 -0
- package/tests/unit/random/random-boolean.spec.ts +25 -0
- package/tests/unit/random/random-integer.spec.ts +32 -0
- package/tests/unit/random/random-number.spec.ts +33 -0
- package/tests/unit/random/random-string.spec.ts +22 -0
- package/tests/unit/request/fetch/browser.spec.ts +222 -0
- package/tests/unit/request/fetch/general.spec.ts +43 -0
- package/tests/unit/request/fetch/nodejs.spec.ts +225 -0
- package/tests/unit/request/request/base.spec.ts +382 -0
- package/tests/unit/request/request/general.spec.ts +160 -0
- package/tests/unit/result/controller.spec.ts +82 -0
- package/tests/unit/result/either.spec.ts +377 -0
- package/tests/unit/result/generator.spec.ts +273 -0
- package/tests/unit/route/router/route.spec.ts +430 -0
- package/tests/unit/route/router/router.spec.ts +407 -0
- package/tests/unit/route/uri/hash.spec.ts +72 -0
- package/tests/unit/route/uri/pathname.spec.ts +146 -0
- package/tests/unit/route/uri/search.spec.ts +107 -0
- package/tests/unit/socket/client.spec.ts +208 -0
- package/tests/unit/socket/server.spec.ts +133 -0
- package/tests/unit/socket/socket-unit-heartbeat.spec.ts +214 -0
- package/tests/unit/tube/helper.spec.ts +139 -0
- package/tests/unit/tube/tube.spec.ts +501 -0
- package/vite.config.ts +2 -1
- package/dist/index.js +0 -50
- package/dist/index.js.map +0 -209
- package/src/random/string.ts +0 -35
- package/tests/unit/random/string.spec.ts +0 -11
package/src/tube/tube.ts
ADDED
|
@@ -0,0 +1,880 @@
|
|
|
1
|
+
import type { LoggerFriendly, LoggerFriendlyOptions } from "#Source/log/index.ts"
|
|
2
|
+
import { Logger } from "#Source/log/index.ts"
|
|
3
|
+
import { scheduleMacroTask } from "#Source/basic/index.ts"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 表示 Tube 中的订阅回调。
|
|
7
|
+
*/
|
|
8
|
+
export type Subscriber<D> = ((data: D) => void) | ((data: D) => Promise<void>)
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 表示用于移除订阅关系的函数。
|
|
12
|
+
*/
|
|
13
|
+
export type Unsubscribe = () => void
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* `open` 事件的订阅配置。
|
|
17
|
+
*/
|
|
18
|
+
export interface OpenEventSubscribeOptions {
|
|
19
|
+
subscriber: Subscriber<void>
|
|
20
|
+
}
|
|
21
|
+
interface OpenEventSubscribeStates {
|
|
22
|
+
subscriber: OpenEventSubscribeOptions["subscriber"]
|
|
23
|
+
unsubscribe: Unsubscribe
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* `close` 事件的订阅配置。
|
|
28
|
+
*/
|
|
29
|
+
export interface CloseEventSubscribeOptions {
|
|
30
|
+
subscriber: Subscriber<void>
|
|
31
|
+
}
|
|
32
|
+
interface CloseEventSubscribeStates {
|
|
33
|
+
subscriber: CloseEventSubscribeOptions["subscriber"]
|
|
34
|
+
unsubscribe: Unsubscribe
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* `start` 事件的订阅配置。
|
|
39
|
+
*/
|
|
40
|
+
export interface StartEventSubscribeOptions {
|
|
41
|
+
subscriber: Subscriber<void>
|
|
42
|
+
}
|
|
43
|
+
interface StartEventSubscribeStates {
|
|
44
|
+
subscriber: StartEventSubscribeOptions["subscriber"]
|
|
45
|
+
unsubscribe: Unsubscribe
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* `end` 事件的订阅配置。
|
|
50
|
+
*/
|
|
51
|
+
export interface EndEventSubscribeOptions {
|
|
52
|
+
subscriber: Subscriber<void>
|
|
53
|
+
}
|
|
54
|
+
interface EndEventSubscribeStates {
|
|
55
|
+
subscriber: EndEventSubscribeOptions["subscriber"]
|
|
56
|
+
unsubscribe: Unsubscribe
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* `error` 事件的订阅配置。
|
|
61
|
+
*/
|
|
62
|
+
export interface ErrorEventSubscribeOptions<E = Error> {
|
|
63
|
+
subscriber: Subscriber<E>
|
|
64
|
+
}
|
|
65
|
+
interface ErrorEventSubscribeStates<E = Error> {
|
|
66
|
+
subscriber: ErrorEventSubscribeOptions<E>["subscriber"]
|
|
67
|
+
unsubscribe: Unsubscribe
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* `wet` 事件的订阅配置。
|
|
72
|
+
*/
|
|
73
|
+
export interface WetEventSubscribeOptions {
|
|
74
|
+
subscriber: Subscriber<void>
|
|
75
|
+
}
|
|
76
|
+
interface WetEventSubscribeStates {
|
|
77
|
+
subscriber: WetEventSubscribeOptions["subscriber"]
|
|
78
|
+
unsubscribe: Unsubscribe
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* 数据事件的订阅配置。
|
|
83
|
+
*/
|
|
84
|
+
export interface DataEventSubscribeOptions<D> {
|
|
85
|
+
subscriber: Subscriber<D>
|
|
86
|
+
/**
|
|
87
|
+
* 是否重放历史记录。
|
|
88
|
+
*
|
|
89
|
+
* @default DataOptions.replayHistory
|
|
90
|
+
*/
|
|
91
|
+
replayHistory?: boolean
|
|
92
|
+
}
|
|
93
|
+
interface DataEventSubscribeStates<D> {
|
|
94
|
+
subscriber: DataEventSubscribeOptions<D>["subscriber"]
|
|
95
|
+
replayHistory: boolean
|
|
96
|
+
unsubscribe: Unsubscribe
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
interface TubeRunningStates {
|
|
100
|
+
/**
|
|
101
|
+
* true: 可以进数据。
|
|
102
|
+
* false: 不可以进数据。
|
|
103
|
+
*/
|
|
104
|
+
isOpen: boolean
|
|
105
|
+
/**
|
|
106
|
+
* true: 数据进入启动。
|
|
107
|
+
* false: 数据进入停止。
|
|
108
|
+
*/
|
|
109
|
+
isStart: boolean
|
|
110
|
+
/**
|
|
111
|
+
* true: 发生错误。
|
|
112
|
+
* false: 未发生错误。
|
|
113
|
+
*/
|
|
114
|
+
isError: boolean
|
|
115
|
+
/**
|
|
116
|
+
* true: 数据为空。
|
|
117
|
+
* false: 数据不为空。
|
|
118
|
+
*/
|
|
119
|
+
isEmpty: boolean
|
|
120
|
+
/**
|
|
121
|
+
* true: 已打开过。
|
|
122
|
+
* false: 未打开过。
|
|
123
|
+
*/
|
|
124
|
+
hasOpened: boolean
|
|
125
|
+
/**
|
|
126
|
+
* true: 已开始过。
|
|
127
|
+
* false: 未开始过。
|
|
128
|
+
*/
|
|
129
|
+
hasStarted: boolean
|
|
130
|
+
/**
|
|
131
|
+
* true: 已结束过。
|
|
132
|
+
* false: 未结束过。
|
|
133
|
+
*/
|
|
134
|
+
hasEnded: boolean
|
|
135
|
+
/**
|
|
136
|
+
* true: 已关闭过。
|
|
137
|
+
* false: 未关闭过。
|
|
138
|
+
*/
|
|
139
|
+
hasClosed: boolean
|
|
140
|
+
}
|
|
141
|
+
interface DataReplayStates<D> {
|
|
142
|
+
dataHistory: D[]
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* `Tube` 的配置项。
|
|
147
|
+
*/
|
|
148
|
+
export interface TubeOptions extends LoggerFriendlyOptions {
|
|
149
|
+
/**
|
|
150
|
+
* @default true
|
|
151
|
+
*/
|
|
152
|
+
autoStartOnOpen?: boolean
|
|
153
|
+
/**
|
|
154
|
+
* @default true
|
|
155
|
+
*/
|
|
156
|
+
autoOpenOnStart?: boolean
|
|
157
|
+
/**
|
|
158
|
+
* @default true
|
|
159
|
+
*/
|
|
160
|
+
autoEndOnClose?: boolean
|
|
161
|
+
/**
|
|
162
|
+
* @default true
|
|
163
|
+
*/
|
|
164
|
+
autoCloseOnEnd?: boolean
|
|
165
|
+
/**
|
|
166
|
+
* @default true
|
|
167
|
+
*/
|
|
168
|
+
autoStartOnData?: boolean
|
|
169
|
+
/**
|
|
170
|
+
* @default true
|
|
171
|
+
*/
|
|
172
|
+
autoOpenOnData?: boolean
|
|
173
|
+
/**
|
|
174
|
+
* @default true
|
|
175
|
+
*/
|
|
176
|
+
autoOpenOnError?: boolean
|
|
177
|
+
/**
|
|
178
|
+
* @default true
|
|
179
|
+
*/
|
|
180
|
+
autoEndOnError?: boolean
|
|
181
|
+
/**
|
|
182
|
+
* @default true
|
|
183
|
+
*/
|
|
184
|
+
autoCloseOnError?: boolean
|
|
185
|
+
/**
|
|
186
|
+
* 保留多少个历史记录。
|
|
187
|
+
*
|
|
188
|
+
* @default 3
|
|
189
|
+
*/
|
|
190
|
+
historyCount: number
|
|
191
|
+
/**
|
|
192
|
+
* 是否重放历史记录。
|
|
193
|
+
*
|
|
194
|
+
* @default false
|
|
195
|
+
*/
|
|
196
|
+
replayHistory: boolean
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* 表示一条带生命周期、错误语义和历史回放能力的数据通道。
|
|
201
|
+
*
|
|
202
|
+
* 一般的事件顺序是:Open - Data - Data - ... - Data - Data - Close。
|
|
203
|
+
* Error 可能出现在 Open 和 Close 之间的任何位置。
|
|
204
|
+
*/
|
|
205
|
+
export class Tube<D, E = Error> implements LoggerFriendly {
|
|
206
|
+
logger: Logger
|
|
207
|
+
|
|
208
|
+
// 基础配置
|
|
209
|
+
protected autoStartOnOpen: boolean
|
|
210
|
+
protected autoOpenOnStart: boolean
|
|
211
|
+
protected autoEndOnClose: boolean
|
|
212
|
+
protected autoCloseOnEnd: boolean
|
|
213
|
+
protected autoStartOnData: boolean
|
|
214
|
+
protected autoOpenOnData: boolean
|
|
215
|
+
protected autoOpenOnError: boolean
|
|
216
|
+
protected autoEndOnError: boolean
|
|
217
|
+
protected autoCloseOnError: boolean
|
|
218
|
+
protected historyCount: number
|
|
219
|
+
protected replayHistory: boolean
|
|
220
|
+
|
|
221
|
+
// 整体状态
|
|
222
|
+
protected runningStates: TubeRunningStates
|
|
223
|
+
|
|
224
|
+
// 事件订阅
|
|
225
|
+
protected openEventSubscribeStatesMap: Map<Subscriber<void>, OpenEventSubscribeStates>
|
|
226
|
+
protected closeEventSubscribeStatesMap: Map<Subscriber<void>, CloseEventSubscribeStates>
|
|
227
|
+
protected startEventSubscribeStatesMap: Map<Subscriber<void>, StartEventSubscribeStates>
|
|
228
|
+
protected endEventSubscribeStatesMap: Map<Subscriber<void>, EndEventSubscribeStates>
|
|
229
|
+
protected errorEventSubscribeStatesMap: Map<Subscriber<E>, ErrorEventSubscribeStates<E>>
|
|
230
|
+
protected wetEventSubscribeStatesMap: Map<Subscriber<void>, WetEventSubscribeStates>
|
|
231
|
+
protected dataEventSubscribeStatesMap: Map<Subscriber<D>, DataEventSubscribeStates<D>>
|
|
232
|
+
|
|
233
|
+
// 其它
|
|
234
|
+
protected errorHistory: E[]
|
|
235
|
+
protected dataHistory: D[]
|
|
236
|
+
protected dataReplayStatesMap: Map<Subscriber<D>, DataReplayStates<D>>
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* 创建一个 Tube 实例。
|
|
240
|
+
*/
|
|
241
|
+
constructor(options: TubeOptions) {
|
|
242
|
+
this.logger = Logger.fromOptions(options).setDefaultName("Tube")
|
|
243
|
+
|
|
244
|
+
this.autoStartOnOpen = options.autoStartOnOpen ?? true
|
|
245
|
+
this.autoOpenOnStart = options.autoOpenOnStart ?? true
|
|
246
|
+
this.autoEndOnClose = options.autoEndOnClose ?? true
|
|
247
|
+
this.autoCloseOnEnd = options.autoCloseOnEnd ?? true
|
|
248
|
+
this.autoStartOnData = options.autoStartOnData ?? true
|
|
249
|
+
this.autoOpenOnData = options.autoOpenOnData ?? true
|
|
250
|
+
this.autoOpenOnError = options.autoOpenOnError ?? true
|
|
251
|
+
this.autoEndOnError = options.autoEndOnError ?? true
|
|
252
|
+
this.autoCloseOnError = options.autoCloseOnError ?? true
|
|
253
|
+
this.historyCount = options.historyCount ?? 3
|
|
254
|
+
this.replayHistory = options.replayHistory ?? false
|
|
255
|
+
|
|
256
|
+
if (this.historyCount < 1) {
|
|
257
|
+
throw new Error("historyCount must be greater than or equal to 1")
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
this.runningStates = {
|
|
261
|
+
isOpen: false,
|
|
262
|
+
isStart: false,
|
|
263
|
+
isError: false,
|
|
264
|
+
isEmpty: true,
|
|
265
|
+
hasOpened: false,
|
|
266
|
+
hasStarted: false,
|
|
267
|
+
hasEnded: false,
|
|
268
|
+
hasClosed: false,
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
this.openEventSubscribeStatesMap = new Map()
|
|
272
|
+
this.closeEventSubscribeStatesMap = new Map()
|
|
273
|
+
this.startEventSubscribeStatesMap = new Map()
|
|
274
|
+
this.endEventSubscribeStatesMap = new Map()
|
|
275
|
+
this.errorEventSubscribeStatesMap = new Map()
|
|
276
|
+
this.wetEventSubscribeStatesMap = new Map()
|
|
277
|
+
this.dataEventSubscribeStatesMap = new Map()
|
|
278
|
+
|
|
279
|
+
this.errorHistory = []
|
|
280
|
+
this.dataHistory = []
|
|
281
|
+
this.dataReplayStatesMap = new Map()
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* 安全地获取最近一条数据;若当前还没有任何数据则抛出错误。
|
|
286
|
+
*
|
|
287
|
+
* 当数据列表为空时,此方法会抛出错误,请妥善处理。
|
|
288
|
+
*
|
|
289
|
+
* 如果不希望错误发生,可以通过 {@link isWet} 方法判断数据列表是否为空。
|
|
290
|
+
*/
|
|
291
|
+
safeGetLatestData(): D {
|
|
292
|
+
const latestData = this.dataHistory.at(-1)
|
|
293
|
+
if (latestData === undefined) {
|
|
294
|
+
throw new Error("latestData is undefined")
|
|
295
|
+
}
|
|
296
|
+
return latestData
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* 安全地获取最近一次错误;若当前还没有错误记录则抛出错误。
|
|
301
|
+
*
|
|
302
|
+
* 当错误列表为空时,此方法会抛出错误,请妥善处理。
|
|
303
|
+
*
|
|
304
|
+
* 如果不希望错误发生,可以通过 {@link isError} 方法判断错误列表是否为空。
|
|
305
|
+
*/
|
|
306
|
+
safeGetLatestError(): E {
|
|
307
|
+
const latestError = this.errorHistory.at(-1)
|
|
308
|
+
if (latestError === undefined) {
|
|
309
|
+
throw new Error("latestError is undefined")
|
|
310
|
+
}
|
|
311
|
+
return latestError
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* 判断 Tube 当前是否处于打开状态。
|
|
316
|
+
*/
|
|
317
|
+
isOpen(): boolean {
|
|
318
|
+
return this.runningStates.isOpen === true
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* 判断 Tube 是否曾经被打开过。
|
|
323
|
+
*/
|
|
324
|
+
hasOpened(): boolean {
|
|
325
|
+
return this.runningStates.hasOpened === true
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* 打开 Tube,并在需要时自动启动。
|
|
330
|
+
*/
|
|
331
|
+
async open(): Promise<void> {
|
|
332
|
+
if (this.isOpen() === true) {
|
|
333
|
+
return
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
if (this.hasClosed() === true) {
|
|
337
|
+
return
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
this.runningStates.isOpen = true
|
|
341
|
+
this.runningStates.hasOpened = true
|
|
342
|
+
this.triggerOpenEventForAll()
|
|
343
|
+
|
|
344
|
+
if (this.autoStartOnOpen === true) {
|
|
345
|
+
await this.start()
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* 判断 Tube 当前是否处于关闭状态。
|
|
351
|
+
*/
|
|
352
|
+
isClose(): boolean {
|
|
353
|
+
return this.runningStates.isOpen === false
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* 判断 Tube 是否曾经被关闭过。
|
|
358
|
+
*/
|
|
359
|
+
hasClosed(): boolean {
|
|
360
|
+
return this.runningStates.hasClosed === true
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* 关闭 Tube,并在需要时自动结束。
|
|
365
|
+
*/
|
|
366
|
+
async close(): Promise<void> {
|
|
367
|
+
if (this.isClose() === true) {
|
|
368
|
+
return
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if (this.autoEndOnClose === true) {
|
|
372
|
+
await this.end()
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
this.runningStates.isOpen = false
|
|
376
|
+
this.runningStates.hasClosed = true
|
|
377
|
+
this.triggerCloseEventForAll()
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* 判断 Tube 当前是否处于启动状态。
|
|
382
|
+
*/
|
|
383
|
+
isStart(): boolean {
|
|
384
|
+
return this.runningStates.isStart === true
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* 判断 Tube 是否曾经进入过启动状态。
|
|
389
|
+
*/
|
|
390
|
+
hasStarted(): boolean {
|
|
391
|
+
return this.runningStates.hasStarted === true
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* 启动 Tube,并在需要时自动打开。
|
|
396
|
+
*/
|
|
397
|
+
async start(): Promise<void> {
|
|
398
|
+
if (this.isStart() === true) {
|
|
399
|
+
return
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
if (this.autoOpenOnStart === true) {
|
|
403
|
+
await this.open()
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
if (this.isOpen() === false) {
|
|
407
|
+
return
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
this.runningStates.isStart = true
|
|
411
|
+
this.runningStates.hasStarted = true
|
|
412
|
+
this.triggerStartEventForAll()
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* 判断 Tube 当前是否处于结束状态。
|
|
417
|
+
*/
|
|
418
|
+
isEnd(): boolean {
|
|
419
|
+
return this.runningStates.isStart === false
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* 判断 Tube 是否曾经结束过。
|
|
424
|
+
*/
|
|
425
|
+
hasEnded(): boolean {
|
|
426
|
+
return this.runningStates.hasEnded === true
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* 结束 Tube,并在需要时自动关闭。
|
|
431
|
+
*/
|
|
432
|
+
async end(): Promise<void> {
|
|
433
|
+
if (this.isEnd() === true) {
|
|
434
|
+
return
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
if (this.isOpen() === false) {
|
|
438
|
+
return
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
this.runningStates.isStart = false
|
|
442
|
+
this.runningStates.hasEnded = true
|
|
443
|
+
this.triggerEndEventForAll()
|
|
444
|
+
|
|
445
|
+
if (this.autoCloseOnEnd === true) {
|
|
446
|
+
await this.close()
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* 判断 Tube 是否已经记录过错误。
|
|
452
|
+
*/
|
|
453
|
+
isError(): boolean {
|
|
454
|
+
return this.runningStates.isError === true
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
protected async error(): Promise<void> {
|
|
458
|
+
if (this.isOpen() === false) {
|
|
459
|
+
if (this.autoOpenOnError === true) {
|
|
460
|
+
await this.open()
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
if (this.isOpen() === false) {
|
|
465
|
+
return
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// NOTE: 允许在错误状态下继续推送数据,且允许发生多次错误。
|
|
469
|
+
// if (this.isError() === true) {
|
|
470
|
+
// return
|
|
471
|
+
// }
|
|
472
|
+
this.runningStates.isError = true
|
|
473
|
+
this.triggerErrorEventForAll()
|
|
474
|
+
|
|
475
|
+
if (this.autoEndOnError === true) {
|
|
476
|
+
await this.end()
|
|
477
|
+
}
|
|
478
|
+
if (this.autoCloseOnError === true) {
|
|
479
|
+
await this.close()
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* 判断 Tube 是否已经接收过至少一条数据。
|
|
485
|
+
*/
|
|
486
|
+
isWet(): boolean {
|
|
487
|
+
return this.runningStates.isEmpty === false
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// oxlint-disable-next-line require-await
|
|
491
|
+
protected async wet(): Promise<void> {
|
|
492
|
+
if (this.isWet() === true) {
|
|
493
|
+
return
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
this.runningStates.isEmpty = false
|
|
497
|
+
this.triggerWetEventForAll()
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
protected async data(): Promise<void> {
|
|
501
|
+
if (this.isOpen() === false) {
|
|
502
|
+
if (this.autoOpenOnData === true) {
|
|
503
|
+
await this.open()
|
|
504
|
+
}
|
|
505
|
+
else {
|
|
506
|
+
return
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
if (this.isOpen() === false) {
|
|
510
|
+
return
|
|
511
|
+
}
|
|
512
|
+
if (this.isStart() === false) {
|
|
513
|
+
if (this.autoStartOnData === true) {
|
|
514
|
+
await this.start()
|
|
515
|
+
}
|
|
516
|
+
else {
|
|
517
|
+
return
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
if (this.isStart() === false) {
|
|
521
|
+
return
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
protected triggerOpenEventForOne(subscriber: OpenEventSubscribeOptions["subscriber"]): void {
|
|
526
|
+
scheduleMacroTask({ task: async () => await subscriber() })
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
protected triggerOpenEventForAll(): void {
|
|
530
|
+
this.openEventSubscribeStatesMap.forEach((subscribeStates) => {
|
|
531
|
+
scheduleMacroTask({ task: async () => await subscribeStates.subscriber() })
|
|
532
|
+
})
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* 订阅 Tube 的 `open` 事件。
|
|
537
|
+
*/
|
|
538
|
+
subscribeOpenEvent(options: OpenEventSubscribeOptions): Unsubscribe {
|
|
539
|
+
const states = this.openEventSubscribeStatesMap.get(options.subscriber)
|
|
540
|
+
if (states !== undefined) {
|
|
541
|
+
return states.unsubscribe
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
const subscriber = options.subscriber
|
|
545
|
+
const unsubscribe = (): void => {
|
|
546
|
+
this.openEventSubscribeStatesMap.delete(subscriber)
|
|
547
|
+
}
|
|
548
|
+
this.openEventSubscribeStatesMap.set(subscriber, {
|
|
549
|
+
subscriber,
|
|
550
|
+
unsubscribe,
|
|
551
|
+
})
|
|
552
|
+
return unsubscribe
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* 取消指定的 `open` 事件订阅。
|
|
557
|
+
*/
|
|
558
|
+
unsubscribeOpenEvent(subscriber: OpenEventSubscribeOptions["subscriber"]): void {
|
|
559
|
+
const subscribeStates = this.openEventSubscribeStatesMap.get(subscriber)
|
|
560
|
+
if (subscribeStates === undefined) {
|
|
561
|
+
return
|
|
562
|
+
}
|
|
563
|
+
subscribeStates.unsubscribe()
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
protected triggerCloseEventForOne(subscriber: CloseEventSubscribeOptions["subscriber"]): void {
|
|
567
|
+
scheduleMacroTask({ task: async () => await subscriber() })
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
protected triggerCloseEventForAll(): void {
|
|
571
|
+
this.closeEventSubscribeStatesMap.forEach((subscribeStates) => {
|
|
572
|
+
scheduleMacroTask({ task: async () => await subscribeStates.subscriber() })
|
|
573
|
+
})
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* 订阅 Tube 的 `close` 事件。
|
|
578
|
+
*/
|
|
579
|
+
subscribeCloseEvent(options: CloseEventSubscribeOptions): Unsubscribe {
|
|
580
|
+
const states = this.closeEventSubscribeStatesMap.get(options.subscriber)
|
|
581
|
+
if (states !== undefined) {
|
|
582
|
+
return states.unsubscribe
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
const subscriber = options.subscriber
|
|
586
|
+
const unsubscribe = (): void => {
|
|
587
|
+
this.closeEventSubscribeStatesMap.delete(subscriber)
|
|
588
|
+
}
|
|
589
|
+
this.closeEventSubscribeStatesMap.set(subscriber, {
|
|
590
|
+
subscriber,
|
|
591
|
+
unsubscribe,
|
|
592
|
+
})
|
|
593
|
+
return unsubscribe
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* 取消指定的 `close` 事件订阅。
|
|
598
|
+
*/
|
|
599
|
+
unsubscribeCloseEvent(subscriber: CloseEventSubscribeOptions["subscriber"]): void {
|
|
600
|
+
const subscribeStates = this.closeEventSubscribeStatesMap.get(subscriber)
|
|
601
|
+
if (subscribeStates === undefined) {
|
|
602
|
+
return
|
|
603
|
+
}
|
|
604
|
+
subscribeStates.unsubscribe()
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
protected triggerStartEventForOne(subscriber: StartEventSubscribeOptions["subscriber"]): void {
|
|
608
|
+
scheduleMacroTask({ task: async () => await subscriber() })
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
protected triggerStartEventForAll(): void {
|
|
612
|
+
this.startEventSubscribeStatesMap.forEach((subscribeStates) => {
|
|
613
|
+
scheduleMacroTask({ task: async () => await subscribeStates.subscriber() })
|
|
614
|
+
})
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* 订阅 Tube 的 `start` 事件。
|
|
619
|
+
*/
|
|
620
|
+
subscribeStartEvent(options: StartEventSubscribeOptions): Unsubscribe {
|
|
621
|
+
const states = this.startEventSubscribeStatesMap.get(options.subscriber)
|
|
622
|
+
if (states !== undefined) {
|
|
623
|
+
return states.unsubscribe
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
const subscriber = options.subscriber
|
|
627
|
+
const unsubscribe = (): void => {
|
|
628
|
+
this.startEventSubscribeStatesMap.delete(subscriber)
|
|
629
|
+
}
|
|
630
|
+
this.startEventSubscribeStatesMap.set(subscriber, {
|
|
631
|
+
subscriber,
|
|
632
|
+
unsubscribe,
|
|
633
|
+
})
|
|
634
|
+
return unsubscribe
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* 取消指定的 `start` 事件订阅。
|
|
639
|
+
*/
|
|
640
|
+
unsubscribeStartEvent(subscriber: StartEventSubscribeOptions["subscriber"]): void {
|
|
641
|
+
const subscribeStates = this.startEventSubscribeStatesMap.get(subscriber)
|
|
642
|
+
if (subscribeStates === undefined) {
|
|
643
|
+
return
|
|
644
|
+
}
|
|
645
|
+
subscribeStates.unsubscribe()
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
protected triggerEndEventForOne(subscriber: EndEventSubscribeOptions["subscriber"]): void {
|
|
649
|
+
scheduleMacroTask({ task: async () => await subscriber() })
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
protected triggerEndEventForAll(): void {
|
|
653
|
+
this.endEventSubscribeStatesMap.forEach((subscribeStates) => {
|
|
654
|
+
scheduleMacroTask({ task: async () => await subscribeStates.subscriber() })
|
|
655
|
+
})
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* 订阅 Tube 的 `end` 事件。
|
|
660
|
+
*/
|
|
661
|
+
subscribeEndEvent(options: EndEventSubscribeOptions): Unsubscribe {
|
|
662
|
+
const states = this.endEventSubscribeStatesMap.get(options.subscriber)
|
|
663
|
+
if (states !== undefined) {
|
|
664
|
+
return states.unsubscribe
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
const subscriber = options.subscriber
|
|
668
|
+
const unsubscribe = (): void => {
|
|
669
|
+
this.endEventSubscribeStatesMap.delete(subscriber)
|
|
670
|
+
}
|
|
671
|
+
this.endEventSubscribeStatesMap.set(subscriber, {
|
|
672
|
+
subscriber,
|
|
673
|
+
unsubscribe,
|
|
674
|
+
})
|
|
675
|
+
return unsubscribe
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
/**
|
|
679
|
+
* 取消指定的 `end` 事件订阅。
|
|
680
|
+
*/
|
|
681
|
+
unsubscribeEndEvent(subscriber: EndEventSubscribeOptions["subscriber"]): void {
|
|
682
|
+
const subscribeStates = this.endEventSubscribeStatesMap.get(subscriber)
|
|
683
|
+
if (subscribeStates === undefined) {
|
|
684
|
+
return
|
|
685
|
+
}
|
|
686
|
+
subscribeStates.unsubscribe()
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
protected triggerWetEventForOne(subscriber: WetEventSubscribeOptions["subscriber"]): void {
|
|
690
|
+
scheduleMacroTask({ task: async () => await subscriber() })
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
protected triggerWetEventForAll(): void {
|
|
694
|
+
this.wetEventSubscribeStatesMap.forEach((subscribeStates) => {
|
|
695
|
+
scheduleMacroTask({ task: async () => await subscribeStates.subscriber() })
|
|
696
|
+
})
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* 订阅 Tube 首次变为非空时触发的 `wet` 事件。
|
|
701
|
+
*/
|
|
702
|
+
subscribeWetEvent(options: WetEventSubscribeOptions): Unsubscribe {
|
|
703
|
+
const states = this.wetEventSubscribeStatesMap.get(options.subscriber)
|
|
704
|
+
if (states !== undefined) {
|
|
705
|
+
return states.unsubscribe
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
const subscriber = options.subscriber
|
|
709
|
+
const unsubscribe = (): void => {
|
|
710
|
+
this.wetEventSubscribeStatesMap.delete(subscriber)
|
|
711
|
+
}
|
|
712
|
+
this.wetEventSubscribeStatesMap.set(subscriber, {
|
|
713
|
+
subscriber,
|
|
714
|
+
unsubscribe,
|
|
715
|
+
})
|
|
716
|
+
return unsubscribe
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
/**
|
|
720
|
+
* 取消指定的 `wet` 事件订阅。
|
|
721
|
+
*/
|
|
722
|
+
unsubscribeWetEvent(subscriber: WetEventSubscribeOptions["subscriber"]): void {
|
|
723
|
+
const subscribeStates = this.wetEventSubscribeStatesMap.get(subscriber)
|
|
724
|
+
if (subscribeStates === undefined) {
|
|
725
|
+
return
|
|
726
|
+
}
|
|
727
|
+
subscribeStates.unsubscribe()
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
/**
|
|
731
|
+
* 向 Tube 推送一个错误,并触发错误生命周期。
|
|
732
|
+
*/
|
|
733
|
+
async pushError(error: E): Promise<void> {
|
|
734
|
+
this.errorHistory.push(error)
|
|
735
|
+
await this.error()
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
protected triggerErrorEventForOne(subscriber: ErrorEventSubscribeOptions<E>["subscriber"]): void {
|
|
739
|
+
const latestErrorData = this.errorHistory.at(-1)
|
|
740
|
+
if (latestErrorData === undefined) {
|
|
741
|
+
throw new Error("latestErrorData is undefined")
|
|
742
|
+
}
|
|
743
|
+
scheduleMacroTask({ task: async () => await subscriber(latestErrorData) })
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
protected triggerErrorEventForAll(): void {
|
|
747
|
+
const latestErrorData = this.errorHistory.at(-1)
|
|
748
|
+
if (latestErrorData === undefined) {
|
|
749
|
+
throw new Error("latestErrorData is undefined")
|
|
750
|
+
}
|
|
751
|
+
this.errorEventSubscribeStatesMap.forEach((subscribeStates) => {
|
|
752
|
+
scheduleMacroTask({ task: async () => await subscribeStates.subscriber(latestErrorData) })
|
|
753
|
+
})
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
/**
|
|
757
|
+
* 订阅 Tube 的 `error` 事件。
|
|
758
|
+
*/
|
|
759
|
+
subscribeErrorEvent(options: ErrorEventSubscribeOptions<E>): Unsubscribe {
|
|
760
|
+
const states = this.errorEventSubscribeStatesMap.get(options.subscriber)
|
|
761
|
+
if (states !== undefined) {
|
|
762
|
+
return states.unsubscribe
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
const subscriber = options.subscriber
|
|
766
|
+
const unsubscribe = (): void => {
|
|
767
|
+
this.errorEventSubscribeStatesMap.delete(subscriber)
|
|
768
|
+
}
|
|
769
|
+
this.errorEventSubscribeStatesMap.set(subscriber, {
|
|
770
|
+
subscriber,
|
|
771
|
+
unsubscribe,
|
|
772
|
+
})
|
|
773
|
+
return unsubscribe
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
/**
|
|
777
|
+
* 取消指定的 `error` 事件订阅。
|
|
778
|
+
*/
|
|
779
|
+
unsubscribeErrorEvent(subscriber: ErrorEventSubscribeOptions<E>["subscriber"]): void {
|
|
780
|
+
const subscribeStates = this.errorEventSubscribeStatesMap.get(subscriber)
|
|
781
|
+
if (subscribeStates === undefined) {
|
|
782
|
+
return
|
|
783
|
+
}
|
|
784
|
+
subscribeStates.unsubscribe()
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
/**
|
|
788
|
+
* 向 Tube 推送一条数据,并在需要时自动打开、启动与变为非空。
|
|
789
|
+
*/
|
|
790
|
+
async pushData(data: D): Promise<void> {
|
|
791
|
+
await this.data()
|
|
792
|
+
|
|
793
|
+
this.dataHistory.push(data)
|
|
794
|
+
if (this.dataHistory.length > this.historyCount) {
|
|
795
|
+
this.dataHistory.shift()
|
|
796
|
+
}
|
|
797
|
+
const allDataEventSubscribeStatesList = Array.from(this.dataEventSubscribeStatesMap.values())
|
|
798
|
+
const replayingDataSubscriberList = Array.from(this.dataReplayStatesMap.keys())
|
|
799
|
+
const notReplayingDataEventSubscribeStatesList = allDataEventSubscribeStatesList.filter((subscribeStates) => {
|
|
800
|
+
return replayingDataSubscriberList.includes(subscribeStates.subscriber) === false
|
|
801
|
+
})
|
|
802
|
+
// 对于不处于重放状态的监听器,直接触发
|
|
803
|
+
notReplayingDataEventSubscribeStatesList.forEach((subscribeStates) => {
|
|
804
|
+
scheduleMacroTask({ task: async () => await subscribeStates.subscriber(data) })
|
|
805
|
+
})
|
|
806
|
+
// 对于处于重放状态的监听器,将数据推入重放队列
|
|
807
|
+
this.dataReplayStatesMap.forEach((replayStates) => {
|
|
808
|
+
replayStates.dataHistory.push(data)
|
|
809
|
+
})
|
|
810
|
+
|
|
811
|
+
if (this.isWet() === false) {
|
|
812
|
+
await this.wet()
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
protected startReplay(subscriber: Subscriber<D>): void {
|
|
817
|
+
const isReplaying = this.dataReplayStatesMap.has(subscriber)
|
|
818
|
+
if (isReplaying === true) {
|
|
819
|
+
return
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
const dataHistoryToReplay = [...this.dataHistory]
|
|
823
|
+
this.dataReplayStatesMap.set(subscriber, { dataHistory: dataHistoryToReplay })
|
|
824
|
+
|
|
825
|
+
scheduleMacroTask({
|
|
826
|
+
task: async () => {
|
|
827
|
+
while (dataHistoryToReplay.length !== 0) {
|
|
828
|
+
const data = dataHistoryToReplay.shift()!
|
|
829
|
+
await subscriber(data)
|
|
830
|
+
}
|
|
831
|
+
await this.stopReplay(subscriber)
|
|
832
|
+
}
|
|
833
|
+
})
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
// oxlint-disable-next-line require-await
|
|
837
|
+
protected async stopReplay(subscriber: Subscriber<D>): Promise<void> {
|
|
838
|
+
this.dataReplayStatesMap.delete(subscriber)
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
/**
|
|
842
|
+
* 订阅 Tube 的数据事件,并可选地重放已有历史。
|
|
843
|
+
*/
|
|
844
|
+
subscribeData(options: DataEventSubscribeOptions<D>): Unsubscribe {
|
|
845
|
+
const states = this.dataEventSubscribeStatesMap.get(options.subscriber)
|
|
846
|
+
if (states !== undefined) {
|
|
847
|
+
return states.unsubscribe
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
const subscriber = options.subscriber
|
|
851
|
+
const replayHistory = options.replayHistory ?? this.replayHistory
|
|
852
|
+
const unsubscribe = (): void => {
|
|
853
|
+
this.dataEventSubscribeStatesMap.delete(subscriber)
|
|
854
|
+
this.dataReplayStatesMap.delete(subscriber)
|
|
855
|
+
}
|
|
856
|
+
this.dataEventSubscribeStatesMap.set(subscriber, {
|
|
857
|
+
subscriber,
|
|
858
|
+
replayHistory,
|
|
859
|
+
unsubscribe,
|
|
860
|
+
})
|
|
861
|
+
|
|
862
|
+
if (replayHistory === true) {
|
|
863
|
+
// NOTE: 开始 Replay 的方法必须同步调用,即第一时间将目标订阅者设为 Replay 状态,避免丢失数据。
|
|
864
|
+
this.startReplay(subscriber)
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
return unsubscribe
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
/**
|
|
871
|
+
* 取消指定的数据订阅。
|
|
872
|
+
*/
|
|
873
|
+
unsubscribeData(subscriber: Subscriber<D>): void {
|
|
874
|
+
const subscribeStates = this.dataEventSubscribeStatesMap.get(subscriber)
|
|
875
|
+
if (subscribeStates === undefined) {
|
|
876
|
+
return
|
|
877
|
+
}
|
|
878
|
+
subscribeStates.unsubscribe()
|
|
879
|
+
}
|
|
880
|
+
}
|