@hile/micro 2.0.3 → 2.0.5
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/dist/application.js +4 -1
- package/dist/registry.js +22 -11
- package/dist/server.d.ts +6 -0
- package/dist/server.js +13 -6
- package/package.json +3 -2
package/dist/application.js
CHANGED
|
@@ -85,15 +85,16 @@ export class Application extends Server {
|
|
|
85
85
|
// 这里不清理 topics 由业务方自己清理
|
|
86
86
|
// 这里也不清理 declare 和 undeclare 由业务方自己清理
|
|
87
87
|
return async () => {
|
|
88
|
+
this.stopped = true;
|
|
88
89
|
for (const fallback of this.fallbacks) {
|
|
89
90
|
fallback();
|
|
90
91
|
}
|
|
91
92
|
this.fallbacks.clear();
|
|
92
|
-
this.stopped = true;
|
|
93
93
|
if (this.reconnectTimeout) {
|
|
94
94
|
clearTimeout(this.reconnectTimeout);
|
|
95
95
|
this.reconnectTimeout = undefined;
|
|
96
96
|
}
|
|
97
|
+
this.registry?.dispose();
|
|
97
98
|
this.registry = undefined;
|
|
98
99
|
await callback();
|
|
99
100
|
};
|
|
@@ -105,6 +106,7 @@ export class Application extends Server {
|
|
|
105
106
|
clearTimeout(this.reconnectTimeout);
|
|
106
107
|
this.reconnectTimeout = setTimeout(() => {
|
|
107
108
|
this.reconnectTimeout = undefined;
|
|
109
|
+
this.logger.debug('[reconnecting] %s:%d', this._registry_address.host, this._registry_address.port);
|
|
108
110
|
void this.reconnectToRegistry().catch(() => {
|
|
109
111
|
if (this.stopped)
|
|
110
112
|
return;
|
|
@@ -140,6 +142,7 @@ export class Application extends Server {
|
|
|
140
142
|
for (const [topic, callback] of this.topics) {
|
|
141
143
|
await this.subscribe(topic, callback, true);
|
|
142
144
|
}
|
|
145
|
+
this.logger.debug('[reconnected] %s:%d', this._registry_address.host, this._registry_address.port);
|
|
143
146
|
})().finally(() => {
|
|
144
147
|
this.registryReconnectPromise = undefined;
|
|
145
148
|
});
|
package/dist/registry.js
CHANGED
|
@@ -3,6 +3,7 @@ import { homedir } from 'node:os';
|
|
|
3
3
|
import { resolve, join } from 'node:path';
|
|
4
4
|
import { existsSync, mkdirSync, readdirSync, readFileSync, watch } from 'node:fs';
|
|
5
5
|
import YAML from 'yaml';
|
|
6
|
+
import { createLogger } from '@hile/logger';
|
|
6
7
|
/** 将 `host:port` 或 `[ipv6]:port` 形式的 key 解析为地址(端口取最后一个 `:` 之后) */
|
|
7
8
|
export function parseAddressKey(key) {
|
|
8
9
|
const i = key.lastIndexOf(':');
|
|
@@ -51,7 +52,12 @@ export class Registry extends Server {
|
|
|
51
52
|
if (!existsSync(workspace)) {
|
|
52
53
|
mkdirSync(workspace, { recursive: true });
|
|
53
54
|
}
|
|
54
|
-
super('registry',
|
|
55
|
+
super('registry', {
|
|
56
|
+
logger: props.logger ?? createLogger({
|
|
57
|
+
level: 'debug',
|
|
58
|
+
pretty: process.env.NODE_ENV !== 'production',
|
|
59
|
+
}), ...props
|
|
60
|
+
});
|
|
55
61
|
this.workspace = workspace;
|
|
56
62
|
this.events.on('connect', (client, extras) => {
|
|
57
63
|
const key = client.host + ':' + client.port;
|
|
@@ -60,17 +66,19 @@ export class Registry extends Server {
|
|
|
60
66
|
this.namespaces.set(namespace, new Set());
|
|
61
67
|
}
|
|
62
68
|
this.namespaces.get(namespace).add(key);
|
|
69
|
+
this.logger.debug('[connect] %s/%s', key, namespace);
|
|
63
70
|
});
|
|
64
71
|
this.events.on('disconnect', (client, extras) => {
|
|
65
72
|
const key = client.host + ':' + client.port;
|
|
66
|
-
// 清理 topic
|
|
67
|
-
for (const [
|
|
68
|
-
if (publishers.has(key))
|
|
73
|
+
// 清理 topic 中的关联(不删除 topic,保留 data 供后续 subscriber 使用)
|
|
74
|
+
for (const [, { publishers, subscribers }] of this.topics) {
|
|
75
|
+
if (publishers.has(key)) {
|
|
69
76
|
publishers.delete(key);
|
|
70
|
-
|
|
77
|
+
this.logger.debug('[delete publisher] %s', key);
|
|
78
|
+
}
|
|
79
|
+
if (subscribers.has(key)) {
|
|
71
80
|
subscribers.delete(key);
|
|
72
|
-
|
|
73
|
-
this.topics.delete(topic);
|
|
81
|
+
this.logger.debug('[delete subscriber] %s', key);
|
|
74
82
|
}
|
|
75
83
|
}
|
|
76
84
|
// 清理 namespace 中的关联
|
|
@@ -79,8 +87,10 @@ export class Registry extends Server {
|
|
|
79
87
|
const keys = this.namespaces.get(namespace);
|
|
80
88
|
if (keys.has(key)) {
|
|
81
89
|
keys.delete(key);
|
|
90
|
+
this.logger.debug('[disconnect] %s/%s', key, namespace);
|
|
82
91
|
if (keys.size === 0) {
|
|
83
92
|
this.namespaces.delete(namespace);
|
|
93
|
+
this.logger.debug('[delete namespace] %s', namespace);
|
|
84
94
|
}
|
|
85
95
|
}
|
|
86
96
|
}
|
|
@@ -186,6 +196,7 @@ export class Registry extends Server {
|
|
|
186
196
|
entry.data = data.payload;
|
|
187
197
|
publishers.add(key);
|
|
188
198
|
this.publish(data.topic, data.payload);
|
|
199
|
+
this.logger.debug('[declare] %s/%s', key, data.topic);
|
|
189
200
|
return Date.now();
|
|
190
201
|
}));
|
|
191
202
|
}
|
|
@@ -200,8 +211,10 @@ export class Registry extends Server {
|
|
|
200
211
|
const i = publishers.size;
|
|
201
212
|
if (publishers.has(key)) {
|
|
202
213
|
publishers.delete(key);
|
|
214
|
+
this.logger.debug('[undeclare] %s/%s', key, data.topic);
|
|
203
215
|
if (publishers.size === 0 && subscribers.size === 0) {
|
|
204
216
|
this.topics.delete(data.topic);
|
|
217
|
+
this.logger.debug('[delete topic] %s', data.topic);
|
|
205
218
|
}
|
|
206
219
|
}
|
|
207
220
|
return i - publishers.size;
|
|
@@ -216,6 +229,7 @@ export class Registry extends Server {
|
|
|
216
229
|
const entry = this.topics.get(data.topic);
|
|
217
230
|
const subscribers = entry.subscribers;
|
|
218
231
|
subscribers.add(key);
|
|
232
|
+
this.logger.debug('[subscribe] %s/%s', key, data.topic);
|
|
219
233
|
return entry.data;
|
|
220
234
|
}));
|
|
221
235
|
}
|
|
@@ -226,14 +240,11 @@ export class Registry extends Server {
|
|
|
226
240
|
return 0;
|
|
227
241
|
const entry = this.topics.get(data.topic);
|
|
228
242
|
const subscribers = entry.subscribers;
|
|
229
|
-
const publishers = entry.publishers;
|
|
230
243
|
const i = subscribers.size;
|
|
231
244
|
if (subscribers.has(key)) {
|
|
232
245
|
subscribers.delete(key);
|
|
233
|
-
if (subscribers.size === 0 && publishers.size === 0) {
|
|
234
|
-
this.topics.delete(data.topic);
|
|
235
|
-
}
|
|
236
246
|
}
|
|
247
|
+
this.logger.debug('[unsubscribe] %s/%s', key, data.topic);
|
|
237
248
|
return i - subscribers.size;
|
|
238
249
|
}));
|
|
239
250
|
}
|
package/dist/server.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { Client } from './client.js';
|
|
|
3
3
|
import { IncomingMessage } from 'http';
|
|
4
4
|
import { EventEmitter } from 'node:events';
|
|
5
5
|
import type { Duplex } from "node:stream";
|
|
6
|
+
import type { Logger } from '@hile/logger';
|
|
6
7
|
/** {@link MessageLoaderProps} 加上出站 WebSocket 宣告地址 */
|
|
7
8
|
export type MicroServerProps = MessageLoaderProps & {
|
|
8
9
|
/**
|
|
@@ -10,11 +11,16 @@ export type MicroServerProps = MessageLoaderProps & {
|
|
|
10
11
|
* 缺省使用 `getLocalIPv4()`;若仍为 `undefined`(无可用 IPv4)则构造 {@link Server} 时抛错。
|
|
11
12
|
*/
|
|
12
13
|
advertiseHost?: string;
|
|
14
|
+
/**
|
|
15
|
+
* 日志记录器
|
|
16
|
+
*/
|
|
17
|
+
logger?: Logger;
|
|
13
18
|
};
|
|
14
19
|
export declare class Server extends MessageLoader {
|
|
15
20
|
readonly namespace: string;
|
|
16
21
|
private wss?;
|
|
17
22
|
port?: number;
|
|
23
|
+
readonly logger: Logger | Console;
|
|
18
24
|
readonly clients: Map<string, Client>;
|
|
19
25
|
private readonly announceHost;
|
|
20
26
|
readonly events: EventEmitter<any>;
|
package/dist/server.js
CHANGED
|
@@ -9,6 +9,7 @@ export class Server extends MessageLoader {
|
|
|
9
9
|
namespace;
|
|
10
10
|
wss;
|
|
11
11
|
port;
|
|
12
|
+
logger;
|
|
12
13
|
clients = new Map();
|
|
13
14
|
announceHost;
|
|
14
15
|
events = new EventEmitter();
|
|
@@ -16,7 +17,7 @@ export class Server extends MessageLoader {
|
|
|
16
17
|
return this.announceHost;
|
|
17
18
|
}
|
|
18
19
|
constructor(namespace, props = {}) {
|
|
19
|
-
const { advertiseHost, ...loaderProps } = props;
|
|
20
|
+
const { advertiseHost, logger, ...loaderProps } = props;
|
|
20
21
|
super(loaderProps);
|
|
21
22
|
this.namespace = namespace;
|
|
22
23
|
const resolved = advertiseHost?.trim() || getLocalIPv4();
|
|
@@ -24,6 +25,7 @@ export class Server extends MessageLoader {
|
|
|
24
25
|
throw new Error('Unable to resolve advertise host for @hile/micro Server: pass `advertiseHost` (e.g. "127.0.0.1") in constructor options, or ensure getLocalIPv4() returns an address.');
|
|
25
26
|
}
|
|
26
27
|
this.announceHost = resolved;
|
|
28
|
+
this.logger = logger ?? console;
|
|
27
29
|
this.events.on('connect', (client, extras) => {
|
|
28
30
|
client.events.emit('connect', extras);
|
|
29
31
|
});
|
|
@@ -133,12 +135,12 @@ export class Server extends MessageLoader {
|
|
|
133
135
|
this.wss = new WebSocketServer({ noServer: true });
|
|
134
136
|
}
|
|
135
137
|
return async () => {
|
|
136
|
-
const toDispose = [...this.clients.values()];
|
|
137
|
-
for (const client of toDispose) {
|
|
138
|
-
client.dispose();
|
|
139
|
-
}
|
|
140
|
-
this.clients.clear();
|
|
141
138
|
if (this.wss) {
|
|
139
|
+
// terminate 立即销毁 socket,不等待对端 close frame
|
|
140
|
+
// 避免 graceful close 时对端无响应导致 HTTP server 无法关闭
|
|
141
|
+
for (const ws of [...this.wss.clients]) {
|
|
142
|
+
ws.terminate();
|
|
143
|
+
}
|
|
142
144
|
await new Promise((resolve, reject) => {
|
|
143
145
|
this.wss.close((err) => {
|
|
144
146
|
if (err)
|
|
@@ -147,6 +149,11 @@ export class Server extends MessageLoader {
|
|
|
147
149
|
});
|
|
148
150
|
});
|
|
149
151
|
}
|
|
152
|
+
const toDispose = [...this.clients.values()];
|
|
153
|
+
for (const client of toDispose) {
|
|
154
|
+
client.dispose();
|
|
155
|
+
}
|
|
156
|
+
this.clients.clear();
|
|
150
157
|
this.wss = undefined;
|
|
151
158
|
this.port = undefined;
|
|
152
159
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hile/micro",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -23,11 +23,12 @@
|
|
|
23
23
|
"vitest": "^4.0.18"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
+
"@hile/logger": "^2.0.1",
|
|
26
27
|
"@hile/message-loader": "^2.0.1",
|
|
27
28
|
"@hile/message-ws": "^2.0.3",
|
|
28
29
|
"internal-ip": "^9.0.0",
|
|
29
30
|
"ws": "^8.21.0",
|
|
30
31
|
"yaml": "^2.9.0"
|
|
31
32
|
},
|
|
32
|
-
"gitHead": "
|
|
33
|
+
"gitHead": "aaa46af05d9fe0d658b4f7a8d54ad8da088a10f6"
|
|
33
34
|
}
|