@lyrify/znl 0.5.2 → 0.6.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/README.md +405 -86
- package/package.json +1 -1
- package/src/ZNL.js +607 -76
- package/src/constants.js +3 -0
- package/src/protocol.js +47 -12
package/src/constants.js
CHANGED
|
@@ -18,6 +18,9 @@ export const CONTROL_AUTH = "__znl_v1_auth__";
|
|
|
18
18
|
/** slave 保活心跳帧标识符(slave → master,定时发送) */
|
|
19
19
|
export const CONTROL_HEARTBEAT = "heartbeat";
|
|
20
20
|
|
|
21
|
+
/** master 心跳应答帧标识符(master → slave,用于确认链路可达) */
|
|
22
|
+
export const CONTROL_HEARTBEAT_ACK = "heartbeat_ack";
|
|
23
|
+
|
|
21
24
|
/** slave 上线注册帧标识符(slave → master,start 时自动发送) */
|
|
22
25
|
export const CONTROL_REGISTER = "register";
|
|
23
26
|
|
package/src/protocol.js
CHANGED
|
@@ -4,11 +4,13 @@
|
|
|
4
4
|
* 负责所有帧的构建与解析,全部为纯函数,无副作用。
|
|
5
5
|
*
|
|
6
6
|
* 控制帧格式:
|
|
7
|
-
* 注册帧:
|
|
8
|
-
* 注销帧:
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
7
|
+
* 注册帧: [PREFIX, "register", (AUTH_MARKER, authKey)?]
|
|
8
|
+
* 注销帧: [PREFIX, "unregister"]
|
|
9
|
+
* 心跳帧: [PREFIX, "heartbeat", (AUTH_MARKER, authProof)?]
|
|
10
|
+
* 心跳应答帧: [PREFIX, "heartbeat_ack", (AUTH_MARKER, authProof)?]
|
|
11
|
+
* 请求帧: [PREFIX, "req", requestId, (AUTH_MARKER, authKey)?, ...payload]
|
|
12
|
+
* 响应帧: [PREFIX, "res", requestId, ...payload]
|
|
13
|
+
* 广播帧: [PREFIX, "pub", topic, ...payload]
|
|
12
14
|
* Router 侧额外在最前面加一帧:[identity, ...]
|
|
13
15
|
*/
|
|
14
16
|
|
|
@@ -21,6 +23,7 @@ import {
|
|
|
21
23
|
CONTROL_UNREGISTER,
|
|
22
24
|
CONTROL_PUB,
|
|
23
25
|
CONTROL_HEARTBEAT,
|
|
26
|
+
CONTROL_HEARTBEAT_ACK,
|
|
24
27
|
EMPTY_BUFFER,
|
|
25
28
|
} from "./constants.js";
|
|
26
29
|
|
|
@@ -180,22 +183,37 @@ export function buildHeartbeatFrames(authProof = "") {
|
|
|
180
183
|
return frames;
|
|
181
184
|
}
|
|
182
185
|
|
|
186
|
+
/**
|
|
187
|
+
* 构建心跳应答控制帧数组(master → slave)
|
|
188
|
+
* 帧结构:[PREFIX, "heartbeat_ack", (AUTH_MARKER, authProof)?]
|
|
189
|
+
*
|
|
190
|
+
* @param {string} [authProof] - 可选认证证明
|
|
191
|
+
* @returns {Array}
|
|
192
|
+
*/
|
|
193
|
+
export function buildHeartbeatAckFrames(authProof = "") {
|
|
194
|
+
const frames = [CONTROL_PREFIX, CONTROL_HEARTBEAT_ACK];
|
|
195
|
+
if (authProof) frames.push(CONTROL_AUTH, authProof);
|
|
196
|
+
return frames;
|
|
197
|
+
}
|
|
198
|
+
|
|
183
199
|
// ─── 帧解析 ───────────────────────────────────────────────────────────────────
|
|
184
200
|
|
|
185
201
|
/**
|
|
186
202
|
* 解析 ZMQ 原始帧,识别控制帧并提取语义字段
|
|
187
203
|
*
|
|
188
204
|
* 返回 kind 说明:
|
|
189
|
-
* - "register"
|
|
190
|
-
* - "unregister"
|
|
191
|
-
* - "
|
|
192
|
-
* - "
|
|
193
|
-
* - "
|
|
194
|
-
* - "
|
|
205
|
+
* - "register" → slave 上线注册(携带可选 authKey)
|
|
206
|
+
* - "unregister" → slave 主动下线注销
|
|
207
|
+
* - "heartbeat" → slave 发起保活心跳
|
|
208
|
+
* - "heartbeat_ack" → master 返回心跳应答
|
|
209
|
+
* - "publish" → master 广播消息(携带 topic)
|
|
210
|
+
* - "request" → 对端主动发起的 RPC 请求
|
|
211
|
+
* - "response" → 对端返回的 RPC 响应(匹配 pending 请求)
|
|
212
|
+
* - "message" → 非控制帧,普通消息透传
|
|
195
213
|
*
|
|
196
214
|
* @param {Array} frames - 不含 identity 帧的帧数组
|
|
197
215
|
* @returns {{
|
|
198
|
-
* kind : "register"|"unregister"|"heartbeat"|"publish"|"request"|"response"|"message",
|
|
216
|
+
* kind : "register"|"unregister"|"heartbeat"|"heartbeat_ack"|"publish"|"request"|"response"|"message",
|
|
199
217
|
* requestId : string|null,
|
|
200
218
|
* authKey : string|null,
|
|
201
219
|
* authProof : string|null,
|
|
@@ -263,6 +281,23 @@ export function parseControlFrames(frames) {
|
|
|
263
281
|
};
|
|
264
282
|
}
|
|
265
283
|
|
|
284
|
+
// ── 心跳应答帧:[PREFIX, "heartbeat_ack"] ─────────────────────────────────
|
|
285
|
+
if (action === CONTROL_HEARTBEAT_ACK) {
|
|
286
|
+
let authProof = null;
|
|
287
|
+
if (frames.length >= 4 && frames[2]?.toString() === CONTROL_AUTH) {
|
|
288
|
+
authProof = frames[3]?.toString() ?? "";
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return {
|
|
292
|
+
kind: "heartbeat_ack",
|
|
293
|
+
requestId: null,
|
|
294
|
+
authKey: null,
|
|
295
|
+
authProof,
|
|
296
|
+
topic: null,
|
|
297
|
+
payloadFrames: [],
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
|
|
266
301
|
// ── 广播帧:[PREFIX, "pub", topic, ...payloadFrames] ─────────────────────
|
|
267
302
|
if (action === CONTROL_PUB && frames.length >= 3) {
|
|
268
303
|
const topic = frames[2]?.toString() ?? "";
|