1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
import { isMaster } from "cluster";
import { Utils } from "../../../Utils";
export type IPCTarget = NodeJS.EventEmitter & { send?: Function };
export type Router = (message: Message) => void | Promise<void>;
export const suffix = isMaster ? Utils.GenerateGuid() : process.env.ipc_suffix;
export interface Message {
name: string;
args?: any;
}
type InternalMessage = Message & { metadata: any };
export type MessageHandler<T extends Message = Message> = (message: T) => any | Promise<any>;
export class PromisifiedIPCManager {
private readonly target: IPCTarget;
private readonly ipc_id = `ipc_id_${suffix}`;
private readonly is_response = `is_response_${suffix}`;
constructor(target: IPCTarget) {
this.target = target;
}
public emit = async (name: string, args?: any, awaitResponse = false): Promise<Error | undefined> => {
if (!this.target.send) {
return new Error("Cannot dispatch when send is undefined.");
}
if (awaitResponse) {
return new Promise(resolve => {
const messageId = Utils.GenerateGuid();
const metadata: any = {};
metadata[this.ipc_id] = messageId;
const responseHandler: MessageHandler<InternalMessage> = ({ args, metadata }) => {
if (metadata[this.is_response] && metadata[this.ipc_id] === messageId) {
this.target.removeListener("message", responseHandler);
resolve(args.error as Error | undefined);
}
};
this.target.addListener("message", responseHandler);
this.target.send?.({ name, args, metadata });
});
} else {
this.target.send?.({ name, args });
}
}
public setRouter = (router: Router) => {
this.target.addListener("message", async ({ name, args, metadata }: InternalMessage) => {
if (name && (!metadata || !metadata[this.is_response])) {
let error: Error | undefined;
try {
await router({ name, args });
} catch (e) {
error = e;
}
if (metadata && this.target.send) {
metadata[this.is_response] = true;
this.target.send({
name,
args: { error },
metadata
});
}
}
});
}
}
export function IPC(target: IPCTarget) {
return new PromisifiedIPCManager(target);
}
|