@nsshunt/stsmessaging 1.0.56 → 1.0.57

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