@nsshunt/stsmessaging 1.0.56 → 1.0.58

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/index.cjs ADDED
@@ -0,0 +1,726 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
+ get: ((k) => from[k]).bind(null, key),
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
+ value: mod,
21
+ enumerable: true
22
+ }) : target, mod));
23
+ //#endregion
24
+ let tiny_emitter = require("tiny-emitter");
25
+ let ioredis = require("ioredis");
26
+ let chalk = require("chalk");
27
+ chalk = __toESM(chalk);
28
+ let _nsshunt_stsutils = require("@nsshunt/stsutils");
29
+ //#region src/messagingManager.ts
30
+ /**
31
+ * todo
32
+ * @typedef {Object} options - todo
33
+ * @property {boolean} [wssServer=false] - Create a web socket server on this worker instance
34
+ */
35
+ var MessagingManager = class {
36
+ #id;
37
+ #options;
38
+ #inflightMessages = {};
39
+ #messageHeader;
40
+ constructor(options) {
41
+ this.#id = globalThis.crypto.randomUUID();
42
+ this.#options = options;
43
+ this.#messageHeader = `__STS__${this.#options.namespace}__${globalThis.crypto.randomUUID()}`;
44
+ }
45
+ get id() {
46
+ return this.#id;
47
+ }
48
+ ReceivedMessageFromMaster(msg) {}
49
+ SendMessageNoResponse = (payload, options) => {
50
+ this.#SendMessageNoResponse(payload, options);
51
+ };
52
+ SendMessage = (payload, options) => {
53
+ return new Promise((resolve, reject) => {
54
+ this.#SendMessage(payload, options, (payload) => {
55
+ resolve(payload.responsePayload);
56
+ }, (payload) => {
57
+ reject(payload.requestPayload);
58
+ });
59
+ });
60
+ };
61
+ #SendMessageNoResponse = (payload, options) => {
62
+ const messageId = globalThis.crypto.randomUUID();
63
+ const requestPayload = {
64
+ header: this.#messageHeader,
65
+ messageId,
66
+ senderId: this.#id,
67
+ senderRole: this.#options.role,
68
+ requestPayload: payload,
69
+ responsePayload: {},
70
+ pid: process.pid.toString(),
71
+ messageType: "REQUEST_NO_RESPONSE"
72
+ };
73
+ this.#options.messageSender(requestPayload, options);
74
+ };
75
+ #SendMessage = (payload, options, callBack, errorCallBack) => {
76
+ const messageId = globalThis.crypto.randomUUID();
77
+ const requestPayload = {
78
+ header: this.#messageHeader,
79
+ messageId,
80
+ senderId: this.#id,
81
+ senderRole: this.#options.role,
82
+ requestPayload: payload,
83
+ responsePayload: {},
84
+ pid: process.pid.toString(),
85
+ messageType: "REQUEST"
86
+ };
87
+ const messageRecord = {
88
+ messageId,
89
+ senderId: this.#id,
90
+ senderRole: this.#options.role,
91
+ requestPayload,
92
+ responses: {},
93
+ startTime: performance.now(),
94
+ endTime: 0,
95
+ timeout: setTimeout(() => {
96
+ setTimeout(() => {
97
+ delete this.#inflightMessages[messageRecord.messageId];
98
+ }, 0).unref();
99
+ errorCallBack(requestPayload);
100
+ }, this.#options.requestResponseMessageTimeout).unref(),
101
+ callBack,
102
+ errorCallBack
103
+ };
104
+ this.#inflightMessages[messageRecord.messageId] = messageRecord;
105
+ this.#options.messageSender(requestPayload, options);
106
+ };
107
+ #ProcessMessage = async (msg, options) => {
108
+ if (msg.header && msg.header.localeCompare(this.#messageHeader) === 0) {
109
+ const message = msg;
110
+ if (this.#inflightMessages[message.messageId]) {
111
+ const inFlightMessageRecord = this.#inflightMessages[message.messageId];
112
+ inFlightMessageRecord.responses[message.senderId] = { ...message };
113
+ let completed = true;
114
+ if (this.#options.ProcessResponseMessage) {
115
+ completed = await this.#options.ProcessResponseMessage(inFlightMessageRecord.responses, options);
116
+ if (completed) {
117
+ inFlightMessageRecord.endTime = performance.now();
118
+ clearTimeout(inFlightMessageRecord.timeout);
119
+ inFlightMessageRecord.callBack({ responsePayload: Object.values(inFlightMessageRecord.responses).map((r) => r.responsePayload) }, options);
120
+ delete this.#inflightMessages[message.messageId];
121
+ }
122
+ } else if (completed) {
123
+ inFlightMessageRecord.endTime = performance.now();
124
+ clearTimeout(inFlightMessageRecord.timeout);
125
+ inFlightMessageRecord.callBack(message, options);
126
+ delete this.#inflightMessages[message.messageId];
127
+ }
128
+ }
129
+ }
130
+ };
131
+ Start = (options) => {
132
+ this.#messageHeader = `__STS__${this.#options.namespace}__${globalThis.crypto.randomUUID()}`;
133
+ this.#options.messageReceiverStart(options);
134
+ };
135
+ Stop = (options) => {
136
+ this.#options.messageReceiverStop(options);
137
+ for (const [, iPCMessageProcessorWorkerRecord] of Object.entries(this.#inflightMessages)) if (iPCMessageProcessorWorkerRecord.timeout) clearTimeout(iPCMessageProcessorWorkerRecord.timeout);
138
+ this.#inflightMessages = {};
139
+ };
140
+ ProcessMessage = async (msg, options) => {
141
+ if (msg.header) {
142
+ const checkName = `__STS__${this.#options.namespace}__`;
143
+ if (msg.header.includes(checkName)) {
144
+ const message = msg;
145
+ if (msg.messageType.localeCompare("REQUEST") === 0 || msg.messageType.localeCompare("REQUEST_NO_RESPONSE") === 0) {
146
+ let processMessage = true;
147
+ if (message.requestPayload.args && message.requestPayload.args.length > 0 && message.requestPayload.args[0].group) {
148
+ const group = message.requestPayload.args[0].group;
149
+ processMessage = this.#options.groups.indexOf(group) === -1 ? false : true;
150
+ }
151
+ if (processMessage) if (msg.messageType.localeCompare("REQUEST_NO_RESPONSE") === 0) this.#options.ProcessRequestMessage(message, options);
152
+ else {
153
+ message.responsePayload = await this.#options.ProcessRequestMessage(message, options);
154
+ message.senderId = this.#id;
155
+ message.messageType = "RESPONSE";
156
+ this.#options.messageSender(message, options);
157
+ }
158
+ } else this.#ProcessMessage(msg, options);
159
+ }
160
+ }
161
+ };
162
+ };
163
+ //#endregion
164
+ //#region src/redisMessageHandler.ts
165
+ var REQUEST_CHANNEL = "__STS__SVC_stsappframework_request";
166
+ var RESPONSE_CHANNEL = "__STS__SVC_stsappframework_response";
167
+ var RedisMessageHandler = class extends tiny_emitter.TinyEmitter {
168
+ #messagingManager = null;
169
+ #options;
170
+ #events = {};
171
+ #requestChannel;
172
+ #responseChannel;
173
+ #ioredisSubscriber;
174
+ #ioredisPublisher;
175
+ #clients = {};
176
+ #pingTimeout = null;
177
+ constructor(options) {
178
+ super();
179
+ this.#options = options;
180
+ this.#requestChannel = REQUEST_CHANNEL;
181
+ this.#responseChannel = RESPONSE_CHANNEL;
182
+ const redisOptions = {
183
+ showFriendlyErrorStack: true,
184
+ maxRetriesPerRequest: 20
185
+ };
186
+ this.#ioredisSubscriber = new ioredis.Redis(this.#options.redisUrl, redisOptions);
187
+ this.#ioredisPublisher = new ioredis.Redis(this.#options.redisUrl, redisOptions);
188
+ this.#ioredisSubscriber.on("error", (error) => {
189
+ this.#LogError(chalk.default.red(`RedisMessageHandler:constructor(): PID: [${process.pid}] Role: [${this.#options.role}] Error (redisSubscriber on error): [${error}]`));
190
+ });
191
+ this.#ioredisPublisher.on("error", (error) => {
192
+ this.#LogError(chalk.default.red(`RedisMessageHandler:constructor(): PID: [${process.pid}] Role: [${this.#options.role}] Error (redisPublisher on error): [${error}]`));
193
+ });
194
+ this.#ioredisSubscriber.subscribe(this.#requestChannel, this.#responseChannel, (error, count) => {
195
+ if (error) this.#LogError(chalk.default.red(`RedisMessageHandler:constructor(): PID: [${process.pid}] Role: [${this.#options.role}] Error - Failed to subscribe: [${error}]`));
196
+ else this.#LogInfo(chalk.default.white(`RedisMessageHandler:constructor(): PID: [${process.pid}] Role: [${this.#options.role}] Subscribed successfully! This client is currently subscribed to ${count} channels.`));
197
+ });
198
+ this.SetupPrimary();
199
+ if (this.#options.role.localeCompare("CLIENT") === 0) {
200
+ const ping = () => {
201
+ this.#pingTimeout = setTimeout(() => {
202
+ const pingData = {
203
+ id: this.#messagingManager.id,
204
+ groups: this.#options.groups
205
+ };
206
+ if (this.#options.extraData) pingData.extraData = this.#options.extraData;
207
+ this.emitNoResponse("ping", pingData);
208
+ ping();
209
+ }, 1e3).unref();
210
+ };
211
+ ping();
212
+ } else this.on("ping", (pingData, callback) => {
213
+ const { id, groups, extraData } = pingData;
214
+ if (this.#clients[id]) {
215
+ clearTimeout(this.#clients[id].timeout);
216
+ this.#clients[id].pingCount++;
217
+ this.#clients[id].timeout = setTimeout(() => {
218
+ delete this.#clients[id];
219
+ }, 2e3);
220
+ this.#clients[id].groups = groups;
221
+ this.#clients[id].extraData = extraData;
222
+ } else this.#clients[id] = {
223
+ id,
224
+ clientConnected: /* @__PURE__ */ new Date(),
225
+ pingCount: 0,
226
+ timeout: setTimeout(() => {
227
+ delete this.#clients[id];
228
+ }, 2e3),
229
+ groups,
230
+ extraData
231
+ };
232
+ });
233
+ }
234
+ #LogInfo(message) {
235
+ this.#options.logger.info(message);
236
+ }
237
+ #LogError(message) {
238
+ this.#options.logger.error(message);
239
+ }
240
+ #processRawMessage = (channel, rawmessage) => {
241
+ const message = JSON.parse(rawmessage);
242
+ this.#messagingManager?.ProcessMessage(message, { channel });
243
+ };
244
+ get clients() {
245
+ return this.#clients;
246
+ }
247
+ get groups() {
248
+ return this.#options.groups;
249
+ }
250
+ AddGroup = (group) => {
251
+ if (this.#options.groups.indexOf(group) === -1) this.#options.groups.push(group);
252
+ };
253
+ RemoveGroup = (group) => {
254
+ const removeIndex = this.#options.groups.indexOf(group);
255
+ if (removeIndex !== -1) this.#options.groups.splice(removeIndex, 1);
256
+ };
257
+ SetupPrimary = () => {
258
+ this.#messagingManager = new MessagingManager({
259
+ logger: this.#options.logger,
260
+ requestResponseMessageTimeout: 5e3,
261
+ namespace: this.#options.namespace,
262
+ role: this.#options.role,
263
+ groups: this.#options.groups,
264
+ messageSender: this.#messageSender,
265
+ ProcessResponseMessage: this.#ProcessResponseMessage,
266
+ ProcessRequestMessage: this.#processPayload,
267
+ messageReceiverStart: (options) => {
268
+ this.#ioredisSubscriber.on("message", this.#processRawMessage);
269
+ },
270
+ messageReceiverStop: (options) => {
271
+ this.#ioredisSubscriber.off("message", this.#processRawMessage);
272
+ }
273
+ });
274
+ };
275
+ #messageSender = (payload, options) => {
276
+ if (payload.messageType.localeCompare("REQUEST") === 0 || payload.messageType.localeCompare("REQUEST_NO_RESPONSE") === 0) this.#ioredisPublisher.publish(this.#requestChannel, JSON.stringify(payload));
277
+ else if (payload.messageType.localeCompare("RESPONSE") === 0) this.#ioredisPublisher.publish(this.#responseChannel, JSON.stringify(payload));
278
+ };
279
+ #ProcessResponseMessage = async (responses, options) => {
280
+ let found = true;
281
+ let requestGroup = null;
282
+ for (const [responseId, response] of Object.entries(responses)) if (response.requestPayload.args.length > 0 && response.requestPayload.args[0].group) {
283
+ requestGroup = response.requestPayload.args[0].group;
284
+ break;
285
+ }
286
+ if (requestGroup) {
287
+ const clientsInGroup = Object.values(this.#clients).filter((c) => {
288
+ if (c.groups.indexOf(requestGroup) === -1) return false;
289
+ return true;
290
+ });
291
+ found = true;
292
+ clientsInGroup.forEach((c) => {
293
+ if (!responses[c.id]) found = false;
294
+ });
295
+ } else {
296
+ const clientsInGroup = Object.values(this.#clients);
297
+ found = true;
298
+ clientsInGroup.forEach((c) => {
299
+ if (!responses[c.id]) found = false;
300
+ });
301
+ }
302
+ return found;
303
+ };
304
+ #processPayload = (payload, options) => {
305
+ return new Promise((resolve, reject) => {
306
+ if (payload.messageType.localeCompare("REQUEST") === 0 || payload.messageType.localeCompare("REQUEST_NO_RESPONSE") === 0) {
307
+ if (payload.requestPayload["__eventName"]) {
308
+ const eventName = payload.requestPayload["__eventName"];
309
+ if (this.#events[eventName]) try {
310
+ if (payload.messageType.localeCompare("REQUEST_NO_RESPONSE") === 0) {
311
+ this.#events[eventName].callback(...payload.requestPayload.args);
312
+ resolve({});
313
+ } else this.#events[eventName].callback(...payload.requestPayload.args, (responseMessage) => {
314
+ resolve(responseMessage);
315
+ });
316
+ } catch (error) {
317
+ reject(error);
318
+ }
319
+ }
320
+ }
321
+ });
322
+ };
323
+ on(event, callback, ctx) {
324
+ if (this.#events[event]) delete this.#events[event];
325
+ const eventObject = {
326
+ event,
327
+ callback,
328
+ ctx
329
+ };
330
+ this.#events[eventObject.event] = eventObject;
331
+ return this;
332
+ }
333
+ off(event, callback) {
334
+ if (this.#events[event]) delete this.#events[event];
335
+ return this;
336
+ }
337
+ Start = () => {
338
+ this.#messagingManager?.Start();
339
+ };
340
+ Stop = () => {
341
+ if (this.#pingTimeout) {
342
+ clearTimeout(this.#pingTimeout);
343
+ this.#pingTimeout = null;
344
+ }
345
+ this.#messagingManager?.Stop();
346
+ this.#ioredisSubscriber.quit();
347
+ this.#ioredisSubscriber.disconnect();
348
+ this.#ioredisPublisher.quit();
349
+ this.#ioredisPublisher.disconnect();
350
+ };
351
+ emit(event, ...args) {
352
+ (async () => {
353
+ try {
354
+ const retVal = await this.#messagingManager?.SendMessage({
355
+ __eventName: event,
356
+ args: args.slice(0, args.length - 1)
357
+ });
358
+ args[args.length - 1](retVal);
359
+ } catch (error) {
360
+ if (this.#options.ignoreEvents) {
361
+ if (this.#options.ignoreEvents.indexOf(error.__eventName) !== -1) return;
362
+ }
363
+ this.#options.logger.error(chalk.default.red(`RedisMessageHandler:emit(): Error: [${JSON.stringify(error)}]`));
364
+ }
365
+ })();
366
+ return this;
367
+ }
368
+ emitWithError(event, args, responseCb, errorCb) {
369
+ (async () => {
370
+ try {
371
+ responseCb(await this.#messagingManager?.SendMessage({
372
+ __eventName: event,
373
+ args: [args]
374
+ }));
375
+ } catch (error) {
376
+ if (this.#options.ignoreEvents) {
377
+ if (this.#options.ignoreEvents.indexOf(error.__eventName) !== -1) return;
378
+ }
379
+ errorCb(error);
380
+ }
381
+ })();
382
+ return this;
383
+ }
384
+ emitex = async (event, ...args) => {
385
+ return this.#messagingManager.SendMessage({
386
+ __eventName: event,
387
+ args
388
+ });
389
+ };
390
+ emitNoResponse = async (event, ...args) => {
391
+ this.#messagingManager.SendMessageNoResponse({
392
+ __eventName: event,
393
+ args
394
+ });
395
+ };
396
+ };
397
+ //#endregion
398
+ //#region src/ipcMessageHandler.ts
399
+ /**
400
+ * IPC Message Handling.
401
+ *
402
+ * This class can be used to support messages between cluster.primary and cluster.worker instances using IPC.
403
+ * This class can be used for both tghe cluster primary and the cluster worker.
404
+ * Note: Currently groups handling is not supported. Use the redis version for this capability.
405
+ */
406
+ var IPCMessageHandler = class extends tiny_emitter.TinyEmitter {
407
+ #messagingManager = null;
408
+ #options;
409
+ #clients = {};
410
+ #events = {};
411
+ #startWorkerOptions;
412
+ constructor(options) {
413
+ super();
414
+ this.#options = options;
415
+ if (options.role.localeCompare("CLIENT") === 0) this.SetupWorker();
416
+ else this.SetupPrimary();
417
+ }
418
+ get __events() {
419
+ return this.#events;
420
+ }
421
+ AddClient = (client) => {
422
+ const id = globalThis.crypto.randomUUID();
423
+ const processMessage = (payload) => {
424
+ this.#messagingManager?.ProcessMessage(payload, { client });
425
+ };
426
+ client.on("message", processMessage);
427
+ this.#clients[id] = {
428
+ client,
429
+ processMessage
430
+ };
431
+ return id;
432
+ };
433
+ RemoveClient = (id) => {
434
+ const clientRecord = this.#clients[id];
435
+ if (clientRecord) {
436
+ clientRecord.client.off("message", clientRecord.processMessage);
437
+ delete this.#clients[id];
438
+ }
439
+ };
440
+ get clients() {
441
+ return this.#clients;
442
+ }
443
+ SetupPrimary = () => {
444
+ this.#messagingManager = new MessagingManager({
445
+ logger: _nsshunt_stsutils.defaultLogger,
446
+ requestResponseMessageTimeout: 5e3,
447
+ namespace: this.#options.namespace,
448
+ role: "SERVER",
449
+ messageSender: (payload, options) => {
450
+ options.client.send(payload);
451
+ },
452
+ ProcessRequestMessage: async (payload, options) => {
453
+ return this.#processPayload(payload, options);
454
+ },
455
+ messageReceiverStart: (options) => {},
456
+ messageReceiverStop: (options) => {},
457
+ groups: []
458
+ });
459
+ };
460
+ #ProcessWorkerMessageRaw = (payload) => {
461
+ this.#messagingManager?.ProcessMessage(payload, this.#startWorkerOptions);
462
+ };
463
+ SetupWorker = () => {
464
+ this.#messagingManager = new MessagingManager({
465
+ logger: _nsshunt_stsutils.defaultLogger,
466
+ requestResponseMessageTimeout: this.#options.requestResponseMessageTimeout,
467
+ namespace: this.#options.namespace,
468
+ role: "CLIENT",
469
+ messageSender: (payload, options) => {
470
+ process.send(payload);
471
+ },
472
+ ProcessRequestMessage: async (payload, options) => {
473
+ return this.#processPayload(payload, options);
474
+ },
475
+ messageReceiverStart: (options) => {
476
+ this.#startWorkerOptions = { ...options };
477
+ process.on("message", this.#ProcessWorkerMessageRaw);
478
+ },
479
+ messageReceiverStop: (options) => {
480
+ process.off("message", this.#ProcessWorkerMessageRaw);
481
+ },
482
+ groups: []
483
+ });
484
+ };
485
+ SendMessage = async (payload) => {
486
+ if (this.#messagingManager) if (this.#options.role.localeCompare("CLIENT") === 0) return this.#messagingManager?.SendMessage(payload, {});
487
+ else {
488
+ const promArray = [];
489
+ for (const [clientId, clientRecord] of Object.entries(this.#clients)) promArray.push(this.#messagingManager?.SendMessage(payload, { client: clientRecord.client }));
490
+ try {
491
+ return { result: await Promise.all(promArray) };
492
+ } catch (error) {
493
+ return {};
494
+ }
495
+ }
496
+ else return {};
497
+ };
498
+ #processPayload = (payload, options) => {
499
+ return new Promise((resolve, reject) => {
500
+ if (payload.messageType.localeCompare("REQUEST") === 0 || payload.messageType.localeCompare("REQUEST_NO_RESPONSE") === 0) {
501
+ if (payload.requestPayload["__eventName"]) {
502
+ const eventName = payload.requestPayload["__eventName"];
503
+ if (this.#events[eventName]) try {
504
+ if (payload.messageType.localeCompare("REQUEST_NO_RESPONSE") === 0) {
505
+ this.#events[eventName].callback(...payload.requestPayload.args);
506
+ resolve({});
507
+ } else this.#events[eventName].callback(...payload.requestPayload.args, (responseMessage) => {
508
+ resolve(responseMessage);
509
+ });
510
+ } catch (error) {
511
+ reject(error);
512
+ }
513
+ }
514
+ }
515
+ });
516
+ };
517
+ on(event, callback, ctx) {
518
+ if (this.#events[event]) delete this.#events[event];
519
+ const eventObject = {
520
+ event,
521
+ callback,
522
+ ctx
523
+ };
524
+ this.#events[eventObject.event] = eventObject;
525
+ return this;
526
+ }
527
+ off(event, callback) {
528
+ if (this.#events[event]) delete this.#events[event];
529
+ return this;
530
+ }
531
+ Start = () => {
532
+ this.#messagingManager?.Start({});
533
+ };
534
+ Stop = () => {
535
+ this.#messagingManager?.Stop({});
536
+ };
537
+ emit(event, ...args) {
538
+ (async () => {
539
+ try {
540
+ const retVal = await this.SendMessage({
541
+ __eventName: event,
542
+ args: args.slice(0, args.length - 1)
543
+ });
544
+ args[args.length - 1](retVal);
545
+ } catch (error) {
546
+ if (this.#options.ignoreEvents) {
547
+ if (this.#options.ignoreEvents.indexOf(error.__eventName) !== -1) return;
548
+ }
549
+ console.log(error);
550
+ this.#options.logger.error(chalk.default.red(`IPCMessageHandler:emit(): Error: [${JSON.stringify(error)}]`));
551
+ }
552
+ })();
553
+ return this;
554
+ }
555
+ emitNoResponse = async (event, ...args) => {
556
+ if (this.#options.role.localeCompare("CLIENT") === 0) this.#messagingManager.SendMessageNoResponse({
557
+ __eventName: event,
558
+ args
559
+ });
560
+ else for (const [clientId, clientRecord] of Object.entries(this.#clients)) this.#messagingManager.SendMessageNoResponse({
561
+ __eventName: event,
562
+ args
563
+ }, { client: clientRecord.client });
564
+ };
565
+ };
566
+ //#endregion
567
+ //#region src/ipcMessageHandlerPair.ts
568
+ /**
569
+ * IPC Message Handling.
570
+ *
571
+ * This class can be used to support messages between cluster.primary and cluster.worker instances using IPC.
572
+ * This class can be used for both tghe cluster primary and the cluster worker.
573
+ * Note: Currently groups handling is not supported. Use the redis version for this capability.
574
+ */
575
+ var IPCMessageHandlerPair = class extends tiny_emitter.TinyEmitter {
576
+ #messagingManager = null;
577
+ #options;
578
+ #worker = null;
579
+ #events = {};
580
+ #startWorkerOptions;
581
+ #startPrimaryWorker = null;
582
+ constructor(options) {
583
+ super();
584
+ this.#options = options;
585
+ if (options.role.localeCompare("CLIENT") === 0) this.SetupWorker();
586
+ else this.SetupPrimary();
587
+ }
588
+ get __events() {
589
+ return this.#events;
590
+ }
591
+ #ProcessPrimaryMessageRaw = (payload) => {
592
+ this.#messagingManager?.ProcessMessage(payload, { worker: this.#startPrimaryWorker });
593
+ };
594
+ SetupPrimary = () => {
595
+ this.#messagingManager = new MessagingManager({
596
+ logger: _nsshunt_stsutils.defaultLogger,
597
+ requestResponseMessageTimeout: 5e3,
598
+ namespace: this.#options.namespace,
599
+ role: "SERVER",
600
+ messageSender: (payload, options) => {
601
+ options.worker.send(payload);
602
+ },
603
+ ProcessRequestMessage: async (payload, options) => {
604
+ return this.#processPayload(payload, options);
605
+ },
606
+ messageReceiverStart: (options) => {
607
+ const worker = options.worker;
608
+ this.#startPrimaryWorker = worker;
609
+ worker.on("message", this.#ProcessPrimaryMessageRaw);
610
+ },
611
+ messageReceiverStop: (options) => {
612
+ options.worker.off("message", this.#ProcessPrimaryMessageRaw);
613
+ },
614
+ groups: []
615
+ });
616
+ };
617
+ #ProcessWorkerMessageRaw = (payload) => {
618
+ this.#messagingManager?.ProcessMessage(payload, this.#startWorkerOptions);
619
+ };
620
+ SetupWorker = () => {
621
+ this.#messagingManager = new MessagingManager({
622
+ logger: _nsshunt_stsutils.defaultLogger,
623
+ requestResponseMessageTimeout: this.#options.requestResponseMessageTimeout,
624
+ namespace: this.#options.namespace,
625
+ role: "CLIENT",
626
+ messageSender: (payload, options) => {
627
+ process.send(payload);
628
+ },
629
+ ProcessRequestMessage: async (payload, options) => {
630
+ return this.#processPayload(payload, options);
631
+ },
632
+ messageReceiverStart: (options) => {
633
+ this.#startWorkerOptions = { ...options };
634
+ process.on("message", this.#ProcessWorkerMessageRaw);
635
+ },
636
+ messageReceiverStop: (options) => {
637
+ process.off("message", this.#ProcessWorkerMessageRaw);
638
+ },
639
+ groups: []
640
+ });
641
+ };
642
+ SendMessage = async (payload) => {
643
+ if (this.#messagingManager) if (this.#worker) return this.#messagingManager?.SendMessage(payload, { worker: this.#worker });
644
+ else return this.#messagingManager?.SendMessage(payload, {});
645
+ else return {};
646
+ };
647
+ #processPayload = (payload, options) => {
648
+ return new Promise((resolve, reject) => {
649
+ if (payload.messageType.localeCompare("REQUEST") === 0 || payload.messageType.localeCompare("REQUEST_NO_RESPONSE") === 0) {
650
+ if (payload.requestPayload["__eventName"]) {
651
+ const eventName = payload.requestPayload["__eventName"];
652
+ if (this.#events[eventName]) try {
653
+ if (payload.messageType.localeCompare("REQUEST_NO_RESPONSE") === 0) {
654
+ this.#events[eventName].callback(...payload.requestPayload.args);
655
+ resolve({});
656
+ } else this.#events[eventName].callback(...payload.requestPayload.args, (responseMessage) => {
657
+ resolve(responseMessage);
658
+ });
659
+ } catch (error) {
660
+ reject(error);
661
+ }
662
+ }
663
+ }
664
+ });
665
+ };
666
+ on(event, callback, ctx) {
667
+ if (this.#events[event]) delete this.#events[event];
668
+ const eventObject = {
669
+ event,
670
+ callback,
671
+ ctx
672
+ };
673
+ this.#events[eventObject.event] = eventObject;
674
+ return this;
675
+ }
676
+ off(event, callback) {
677
+ if (this.#events[event]) delete this.#events[event];
678
+ return this;
679
+ }
680
+ Start = (worker) => {
681
+ if (worker) {
682
+ this.#messagingManager?.Start({ worker });
683
+ this.#worker = worker;
684
+ } else this.#messagingManager?.Start({});
685
+ };
686
+ Stop = () => {
687
+ if (this.#worker) {
688
+ this.#messagingManager?.Stop({ worker: this.#worker });
689
+ this.#worker = null;
690
+ } else this.#messagingManager?.Stop({});
691
+ };
692
+ get worker() {
693
+ return this.#worker;
694
+ }
695
+ emit(event, ...args) {
696
+ (async () => {
697
+ try {
698
+ const retVal = await this.SendMessage({
699
+ __eventName: event,
700
+ args: args.slice(0, args.length - 1)
701
+ });
702
+ args[args.length - 1](retVal);
703
+ } catch (error) {
704
+ if (this.#options.ignoreEvents) {
705
+ if (this.#options.ignoreEvents.indexOf(error.__eventName) !== -1) return;
706
+ }
707
+ console.log(error);
708
+ this.#options.logger.error(chalk.default.red(`IPCMessageHandler:emit(): Error: [${JSON.stringify(error)}]`));
709
+ }
710
+ })();
711
+ return this;
712
+ }
713
+ emitNoResponse = async (event, ...args) => {
714
+ this.#messagingManager.SendMessageNoResponse({
715
+ __eventName: event,
716
+ args
717
+ });
718
+ };
719
+ };
720
+ //#endregion
721
+ exports.IPCMessageHandler = IPCMessageHandler;
722
+ exports.IPCMessageHandlerPair = IPCMessageHandlerPair;
723
+ exports.MessagingManager = MessagingManager;
724
+ exports.RedisMessageHandler = RedisMessageHandler;
725
+
726
+ //# sourceMappingURL=index.cjs.map