@3fv/electron-utility-process-manager 1.0.7 → 1.1.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 +45 -6
- package/lib/cjs/common/clients.d.ts +23 -1
- package/lib/cjs/common/clients.js +21 -2
- package/lib/cjs/common/clients.js.map +1 -1
- package/lib/cjs/common/events.d.ts +23 -0
- package/lib/cjs/common/events.js +48 -0
- package/lib/cjs/common/events.js.map +1 -0
- package/lib/cjs/common/index.d.ts +1 -0
- package/lib/cjs/common/index.js +1 -0
- package/lib/cjs/common/index.js.map +1 -1
- package/lib/cjs/common/types.d.ts +5 -0
- package/lib/cjs/main/UPMMainService.d.ts +19 -4
- package/lib/cjs/main/UPMMainService.js +33 -8
- package/lib/cjs/main/UPMMainService.js.map +1 -1
- package/lib/cjs/main/UPMMainServiceManager.js +1 -1
- package/lib/cjs/main/UPMMainServiceManager.js.map +1 -1
- package/lib/cjs/node/UPMNodeProcess.d.ts +23 -0
- package/lib/cjs/node/UPMNodeProcess.js +64 -9
- package/lib/cjs/node/UPMNodeProcess.js.map +1 -1
- package/lib/cjs/renderer/UPMRendererClientFactory.js +1 -1
- package/lib/cjs/renderer/UPMRendererClientFactory.js.map +1 -1
- package/lib/mjs/common/clients.d.ts +23 -1
- package/lib/mjs/common/clients.js +21 -2
- package/lib/mjs/common/clients.js.map +1 -1
- package/lib/mjs/common/events.d.ts +23 -0
- package/lib/mjs/common/events.js +41 -0
- package/lib/mjs/common/events.js.map +1 -0
- package/lib/mjs/common/index.d.ts +1 -0
- package/lib/mjs/common/index.js +1 -0
- package/lib/mjs/common/index.js.map +1 -1
- package/lib/mjs/common/types.d.ts +5 -0
- package/lib/mjs/main/UPMMainService.d.ts +19 -4
- package/lib/mjs/main/UPMMainService.js +34 -9
- package/lib/mjs/main/UPMMainService.js.map +1 -1
- package/lib/mjs/main/UPMMainServiceManager.js +1 -1
- package/lib/mjs/main/UPMMainServiceManager.js.map +1 -1
- package/lib/mjs/node/UPMNodeProcess.d.ts +23 -0
- package/lib/mjs/node/UPMNodeProcess.js +63 -8
- package/lib/mjs/node/UPMNodeProcess.js.map +1 -1
- package/lib/mjs/renderer/UPMRendererClientFactory.js +1 -1
- package/lib/mjs/renderer/UPMRendererClientFactory.js.map +1 -1
- package/package.json +7 -6
- package/src/common/clients.ts +42 -2
- package/src/common/events.ts +43 -0
- package/src/common/index.ts +1 -0
- package/src/common/types.ts +6 -0
- package/src/main/UPMMainService.ts +41 -9
- package/src/main/UPMMainServiceManager.ts +1 -1
- package/src/node/UPMNodeProcess.ts +73 -8
- package/src/renderer/UPMRendererClientFactory.ts +1 -1
|
@@ -1,15 +1,38 @@
|
|
|
1
1
|
import * as UPM from "../common/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* `clientId` of the main process, which is
|
|
4
|
+
* reached through `process.parentPort`
|
|
5
|
+
*/
|
|
6
|
+
export declare const MainClientId = "main";
|
|
2
7
|
export declare class UPMNodeProcess {
|
|
3
8
|
readonly processPort: Electron.ParentPort;
|
|
4
9
|
private readonly clientPorts_;
|
|
5
10
|
private readonly requestHandlers_;
|
|
6
11
|
private readonly eventHandlers_;
|
|
12
|
+
private messageIdSeq_;
|
|
7
13
|
private onServiceClientPort;
|
|
8
14
|
private onServiceMessage;
|
|
9
15
|
private onMessage;
|
|
10
16
|
private constructor();
|
|
11
17
|
addRequestHandler<ReqMap extends UPM.MessageRequestMap = any, Type extends UPM.MessageRequestNames<ReqMap> = UPM.MessageRequestNames<ReqMap>>(type: Type, handler: UPM.RequestHandler<ReqMap, Type>): void;
|
|
12
18
|
addEventHandler(handler: UPM.EventHandler): void;
|
|
19
|
+
/**
|
|
20
|
+
* The `clientId` of every client which can currently
|
|
21
|
+
* be pushed an event: the main process (`MainClientId`)
|
|
22
|
+
* and each client with an open port
|
|
23
|
+
*/
|
|
24
|
+
get clientIds(): string[];
|
|
25
|
+
/**
|
|
26
|
+
* Push an event from the `utilityProcess` to its clients
|
|
27
|
+
* as `fire-and-forget`; a client receives it through
|
|
28
|
+
* the handlers it registered with `addEventHandler`.
|
|
29
|
+
*
|
|
30
|
+
* @param data any structured-cloneable value
|
|
31
|
+
* @param clientIds the clients to push to, every client
|
|
32
|
+
* (the main process included) when none are given
|
|
33
|
+
* @returns the `clientId` of each client the event was posted to
|
|
34
|
+
*/
|
|
35
|
+
sendEvent(data: any, ...clientIds: string[]): string[];
|
|
13
36
|
/**
|
|
14
37
|
* Singleton instance
|
|
15
38
|
*
|
|
@@ -3,26 +3,40 @@ import { match } from "ts-pattern";
|
|
|
3
3
|
import * as UPM from "../common/index.js";
|
|
4
4
|
import Tracer from "tracer";
|
|
5
5
|
import { Future } from "@3fv/prelude-ts";
|
|
6
|
-
const log = Tracer.colorConsole();
|
|
6
|
+
const log = Tracer.colorConsole({ level: "info" });
|
|
7
|
+
/**
|
|
8
|
+
* `clientId` of the main process, which is
|
|
9
|
+
* reached through `process.parentPort`
|
|
10
|
+
*/
|
|
11
|
+
export const MainClientId = "main";
|
|
7
12
|
export class UPMNodeProcess {
|
|
8
13
|
onServiceClientPort(clientId, port) {
|
|
9
14
|
log.info(`Received new client port for clientId (${clientId})`);
|
|
10
|
-
|
|
15
|
+
// A CLIENT WHICH RECONNECTS (i.e. A RELOADED RENDERER) REPLACES ITS PORT
|
|
16
|
+
const existingPort = this.clientPorts_.get(clientId);
|
|
17
|
+
if (existingPort) {
|
|
18
|
+
log.warn(`Replacing the port registered for clientId (${clientId})`);
|
|
19
|
+
this.clientPorts_.delete(clientId);
|
|
20
|
+
existingPort.close();
|
|
21
|
+
}
|
|
22
|
+
this.clientPorts_.set(clientId, port);
|
|
11
23
|
port.on("message", (ev) => {
|
|
12
24
|
var _a, _b;
|
|
13
25
|
const envelope = ((_b = (_a = ev.data) === null || _a === void 0 ? void 0 : _a.message) !== null && _b !== void 0 ? _b : ev.data), { channel, payload } = envelope;
|
|
14
|
-
log.
|
|
26
|
+
log.debug(`Message received on client port (${clientId})`, envelope);
|
|
15
27
|
assert(channel === UPM.IPCChannel.UPMServiceMessage, `Only IPCChannel.UPMServiceMessage are allowed on client ports: ${channel}`);
|
|
16
28
|
Future.of(this.onServiceMessage(clientId, port, payload))
|
|
17
29
|
.onFailure(err => log.error(`Unable to handle message`, err));
|
|
18
30
|
});
|
|
19
31
|
port.on("close", () => {
|
|
20
|
-
this.clientPorts_.
|
|
32
|
+
if (this.clientPorts_.get(clientId) === port) {
|
|
33
|
+
this.clientPorts_.delete(clientId);
|
|
34
|
+
}
|
|
21
35
|
});
|
|
22
36
|
port.start();
|
|
23
37
|
}
|
|
24
38
|
async onServiceMessage(clientId, port, payload) {
|
|
25
|
-
log.
|
|
39
|
+
log.debug(`onServiceMessage from (clientId=${clientId})`, payload);
|
|
26
40
|
const { messageId, kind, args, eventData, type } = payload;
|
|
27
41
|
await match(kind)
|
|
28
42
|
.with(UPM.MessageKind.Request, async () => {
|
|
@@ -65,7 +79,7 @@ export class UPMNodeProcess {
|
|
|
65
79
|
res = await resPromise;
|
|
66
80
|
}
|
|
67
81
|
if (res === true) {
|
|
68
|
-
log.
|
|
82
|
+
log.debug(`Successfully handled (${messageId}) event`);
|
|
69
83
|
return;
|
|
70
84
|
}
|
|
71
85
|
}
|
|
@@ -80,10 +94,10 @@ export class UPMNodeProcess {
|
|
|
80
94
|
}
|
|
81
95
|
onMessage(port, message) {
|
|
82
96
|
var _a, _b;
|
|
83
|
-
log.
|
|
97
|
+
log.debug(`Message received on utilityProcess`, message.data);
|
|
84
98
|
const { channel, payload } = ((_b = (_a = message.data) === null || _a === void 0 ? void 0 : _a.message) !== null && _b !== void 0 ? _b : message.data);
|
|
85
99
|
match(channel)
|
|
86
|
-
.when(c => c === UPM.IPCChannel.UPMServiceMessage, () => this.onServiceMessage(
|
|
100
|
+
.when(c => c === UPM.IPCChannel.UPMServiceMessage, () => this.onServiceMessage(MainClientId, port, payload))
|
|
87
101
|
.when(c => c === UPM.IPCChannel.UPMServiceNewClient, () => this.onServiceClientPort(payload.clientId, message.ports[0]))
|
|
88
102
|
.otherwise(c => {
|
|
89
103
|
log.error(`Unknown channel (${c})`);
|
|
@@ -94,6 +108,7 @@ export class UPMNodeProcess {
|
|
|
94
108
|
this.clientPorts_ = new Map();
|
|
95
109
|
this.requestHandlers_ = new Map();
|
|
96
110
|
this.eventHandlers_ = Array();
|
|
111
|
+
this.messageIdSeq_ = 0;
|
|
97
112
|
this.processPort.on("message", (message) => this.onMessage(this.processPort, message));
|
|
98
113
|
}
|
|
99
114
|
addRequestHandler(type, handler) {
|
|
@@ -104,6 +119,46 @@ export class UPMNodeProcess {
|
|
|
104
119
|
log.info(`Registering event handler`);
|
|
105
120
|
this.eventHandlers_.push(handler);
|
|
106
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* The `clientId` of every client which can currently
|
|
124
|
+
* be pushed an event: the main process (`MainClientId`)
|
|
125
|
+
* and each client with an open port
|
|
126
|
+
*/
|
|
127
|
+
get clientIds() {
|
|
128
|
+
return [MainClientId, ...this.clientPorts_.keys()];
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Push an event from the `utilityProcess` to its clients
|
|
132
|
+
* as `fire-and-forget`; a client receives it through
|
|
133
|
+
* the handlers it registered with `addEventHandler`.
|
|
134
|
+
*
|
|
135
|
+
* @param data any structured-cloneable value
|
|
136
|
+
* @param clientIds the clients to push to, every client
|
|
137
|
+
* (the main process included) when none are given
|
|
138
|
+
* @returns the `clientId` of each client the event was posted to
|
|
139
|
+
*/
|
|
140
|
+
sendEvent(data, ...clientIds) {
|
|
141
|
+
const messageId = this.messageIdSeq_++, envelope = {
|
|
142
|
+
channel: UPM.IPCChannel.UPMServiceMessage,
|
|
143
|
+
payload: { messageId, eventData: data, kind: UPM.MessageKind.Event }
|
|
144
|
+
}, targetIds = clientIds.length ? [...new Set(clientIds)] : this.clientIds, sentIds = Array();
|
|
145
|
+
for (const clientId of targetIds) {
|
|
146
|
+
const port = clientId === MainClientId ? this.processPort : this.clientPorts_.get(clientId);
|
|
147
|
+
if (!port) {
|
|
148
|
+
log.warn(`Unable to send event (${messageId}), no port for clientId (${clientId})`);
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
try {
|
|
152
|
+
port.postMessage(envelope);
|
|
153
|
+
sentIds.push(clientId);
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
log.error(`Unable to send event (${messageId}) to clientId (${clientId})`, err);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
log.debug(`Sent event (${messageId}) to clients`, sentIds);
|
|
160
|
+
return sentIds;
|
|
161
|
+
}
|
|
107
162
|
/**
|
|
108
163
|
* Get singleton instance
|
|
109
164
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UPMNodeProcess.js","sourceRoot":"","sources":["../../../src/node/UPMNodeProcess.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,KAAK,GAAG,MAAM,oBAAoB,CAAA;AACzC,OAAO,MAAM,MAAM,QAAQ,CAAA;AAC3B,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAExC,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,EAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"UPMNodeProcess.js","sourceRoot":"","sources":["../../../src/node/UPMNodeProcess.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@ import { Deferred } from "@3fv/deferred";
|
|
|
3
3
|
import { ipcRenderer } from "electron";
|
|
4
4
|
import { assert } from "@3fv/guard";
|
|
5
5
|
import Tracer from "tracer";
|
|
6
|
-
const log = Tracer.colorConsole();
|
|
6
|
+
const log = Tracer.colorConsole({ level: "info" });
|
|
7
7
|
export class UPMRendererClientFactory {
|
|
8
8
|
static async createClient(serviceName, clientId = "renderer") {
|
|
9
9
|
const deferred = new Deferred();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UPMRendererClientFactory.js","sourceRoot":"","sources":["../../../src/renderer/UPMRendererClientFactory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,oBAAoB,CAAA;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AACnC,OAAO,MAAM,MAAM,QAAQ,CAAA;AAE3B,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,EAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"UPMRendererClientFactory.js","sourceRoot":"","sources":["../../../src/renderer/UPMRendererClientFactory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,oBAAoB,CAAA;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AACnC,OAAO,MAAM,MAAM,QAAQ,CAAA;AAE3B,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;AAElD,MAAM,OAAO,wBAAwB;IAEnC,MAAM,CAAC,KAAK,CAAC,YAAY,CAGvB,WAAmB,EAAE,WAAmB,UAAU;QAClD,MAAM,QAAQ,GAAI,IAAI,QAAQ,EAAuC,CAAA;QAErE,MAAM,WAAW,GAAG,CAAC,EAA6B,EAAE,IAA4C,EAAE,EAAE;YAClG,IAAI,CAAC;gBACH,MAAM,EAAC,WAAW,EAAE,eAAe,EAAE,QAAQ,EAAE,YAAY,EAAC,GAAG,IAAI,CAAA;gBAEnE,GAAG,CAAC,IAAI,CAAC,2CAA2C,WAAW,oBAAoB,eAAe,aAAa,QAAQ,iBAAiB,YAAY,GAAG,CAAC,CAAA;gBAGxJ,IAAI,WAAW,KAAK,eAAe,IAAI,QAAQ,KAAK,YAAY,EAAE,CAAC;oBACjE,GAAG,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAA;oBACpC,IAAI,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;wBAC1B,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC,CAAA;oBAC9D,CAAC;yBAAM,CAAC;wBACN,MAAM,IAAI,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;wBACxB,QAAQ,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,iBAAiB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAA;oBAC7D,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,GAAG,CAAC,KAAK,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAA;gBACnC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YACtB,CAAC;QACH,CAAC,CAAA;QAED,IAAI,CAAC;YACH,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAA;YAC/D,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,mBAAmB,EAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;YAE1E,MAAM,aAAa,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAA;YAC5C,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,EAAE,+CAA+C,CAAC,CAAA;QAC/E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YACpB,MAAM,GAAG,CAAA;QACX,CAAC;gBAAS,CAAC;YACT,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAA;QAClE,CAAC;QAED,OAAO,QAAQ,CAAC,OAAO,CAAA;IACzB,CAAC;CAEF;AAED,eAAe,wBAAwB,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@3fv/electron-utility-process-manager",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"packageManager": "pnpm@12.15.0",
|
|
5
5
|
"description": "electron-utility-process-manager",
|
|
6
6
|
"author": "Jonathan Glanz",
|
|
@@ -84,11 +84,10 @@
|
|
|
84
84
|
"build:watch": "pnpm run build --watch",
|
|
85
85
|
"build:examples": "pnpm --filter @3fv/electron-utility-process-manager-examples run build",
|
|
86
86
|
"example": "node ./scripts/run-example.mjs",
|
|
87
|
-
"test": "jest
|
|
87
|
+
"test": "jest",
|
|
88
88
|
"test:watch": "jest --watchAll --no-cache",
|
|
89
89
|
"test:dev": "run-s build && run-p test:watch build:watch",
|
|
90
|
-
"preversion": "pnpm build",
|
|
91
|
-
"preversion::with-tests": "pnpm build && pnpm test",
|
|
90
|
+
"preversion": "pnpm build && pnpm test",
|
|
92
91
|
"release": "gh workflow run release.yml --ref master -f bump=patch"
|
|
93
92
|
},
|
|
94
93
|
"publishConfig": {
|
|
@@ -105,8 +104,10 @@
|
|
|
105
104
|
],
|
|
106
105
|
"files": [
|
|
107
106
|
"lib",
|
|
107
|
+
"!lib/**/*.spec.*",
|
|
108
108
|
"!lib/**/*.tsbuildinfo",
|
|
109
109
|
"src",
|
|
110
|
+
"!src/**/*.spec.ts",
|
|
110
111
|
"README.md"
|
|
111
112
|
],
|
|
112
113
|
"dependencies": {
|
|
@@ -120,7 +121,7 @@
|
|
|
120
121
|
"ts-pattern": "^5.5.0"
|
|
121
122
|
},
|
|
122
123
|
"peerDependencies": {
|
|
123
|
-
"electron": "
|
|
124
|
+
"electron": ">=31"
|
|
124
125
|
},
|
|
125
126
|
"devDependencies": {
|
|
126
127
|
"@faker-js/faker": "^8.4.1",
|
|
@@ -131,7 +132,7 @@
|
|
|
131
132
|
"@types/node": "^22.9.0",
|
|
132
133
|
"@types/shelljs": "^0.8.15",
|
|
133
134
|
"cross-env": "^7.0.3",
|
|
134
|
-
"electron": "
|
|
135
|
+
"electron": "45.3.2",
|
|
135
136
|
"electronmon": "^2.0.3",
|
|
136
137
|
"jest": "^30.5.2",
|
|
137
138
|
"lodash": "^4.17.21",
|
package/src/common/clients.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { isDefined, isFunction } from "@3fv/guard"
|
|
2
2
|
import { isMessagePort, isUtilityProcess } from "./guards.js"
|
|
3
3
|
import Tracer from "tracer"
|
|
4
|
+
import { ClientEventHandlers } from "./events.js"
|
|
4
5
|
import {
|
|
6
|
+
ClientEventHandler,
|
|
5
7
|
Defaults,
|
|
6
8
|
IPCChannel,
|
|
7
9
|
Message, MessageKind, MessageRequestFn,
|
|
@@ -13,7 +15,7 @@ import {
|
|
|
13
15
|
} from "./types.js"
|
|
14
16
|
import { Deferred } from "@3fv/deferred"
|
|
15
17
|
|
|
16
|
-
const log = Tracer.colorConsole()
|
|
18
|
+
const log = Tracer.colorConsole({ level: "info" })
|
|
17
19
|
|
|
18
20
|
/**
|
|
19
21
|
* Service client interface maps a `MessageRequestMap`
|
|
@@ -46,6 +48,22 @@ export interface IMessageClient<
|
|
|
46
48
|
*/
|
|
47
49
|
sendEvent(data: any): void
|
|
48
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Register a handler for events pushed by the
|
|
53
|
+
* `utilityProcess` (`UPMNodeProcess.sendEvent`)
|
|
54
|
+
*
|
|
55
|
+
* @param handler
|
|
56
|
+
* @returns a function which removes the handler
|
|
57
|
+
*/
|
|
58
|
+
addEventHandler(handler: ClientEventHandler): () => void
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Remove a handler registered with `addEventHandler`
|
|
62
|
+
*
|
|
63
|
+
* @param handler
|
|
64
|
+
*/
|
|
65
|
+
removeEventHandler(handler: ClientEventHandler): void
|
|
66
|
+
|
|
49
67
|
/**
|
|
50
68
|
* Execute a request, with a response expected
|
|
51
69
|
*
|
|
@@ -105,6 +123,13 @@ export class MessagePortClient<
|
|
|
105
123
|
*/
|
|
106
124
|
private readonly pendingMessages_ = new Map<number, PendingRequestMessage>()
|
|
107
125
|
|
|
126
|
+
/**
|
|
127
|
+
* Handlers for events pushed by the `utilityProcess`
|
|
128
|
+
*
|
|
129
|
+
* @private
|
|
130
|
+
*/
|
|
131
|
+
private readonly eventHandlers_ = new ClientEventHandlers()
|
|
132
|
+
|
|
108
133
|
/**
|
|
109
134
|
* Get the next `messageId`
|
|
110
135
|
*
|
|
@@ -159,10 +184,17 @@ export class MessagePortClient<
|
|
|
159
184
|
) as [string, Message<ReqMap, Type>],
|
|
160
185
|
{ messageId, result, error } = payload
|
|
161
186
|
|
|
187
|
+
// EVENT PUSHED BY THE `utilityProcess`
|
|
188
|
+
if (payload?.kind === MessageKind.Event) {
|
|
189
|
+
log.debug(`Event received (clientId=${this.clientId},messageId=${messageId})`)
|
|
190
|
+
this.eventHandlers_.dispatch(payload.eventData)
|
|
191
|
+
return
|
|
192
|
+
}
|
|
193
|
+
|
|
162
194
|
try {
|
|
163
195
|
const pending = this.pendingMessages_.get(messageId)
|
|
164
196
|
if (!pending) {
|
|
165
|
-
log.
|
|
197
|
+
log.debug(`Unable to find pending record ${messageId}`)
|
|
166
198
|
return
|
|
167
199
|
}
|
|
168
200
|
|
|
@@ -194,6 +226,14 @@ export class MessagePortClient<
|
|
|
194
226
|
this.port.postMessage(payload)
|
|
195
227
|
}
|
|
196
228
|
|
|
229
|
+
addEventHandler(handler: ClientEventHandler): () => void {
|
|
230
|
+
return this.eventHandlers_.add(handler)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
removeEventHandler(handler: ClientEventHandler): void {
|
|
234
|
+
this.eventHandlers_.remove(handler)
|
|
235
|
+
}
|
|
236
|
+
|
|
197
237
|
async executeRequest<
|
|
198
238
|
Type extends MType,
|
|
199
239
|
R extends MessageRequestReturnType<ReqMap, Type> = MessageRequestReturnType<ReqMap, Type>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import Tracer from "tracer"
|
|
2
|
+
import type { ClientEventHandler } from "./types.js"
|
|
3
|
+
|
|
4
|
+
const log = Tracer.colorConsole({ level: "info" })
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Holds the handlers a client registered for
|
|
8
|
+
* events pushed by the `utilityProcess`
|
|
9
|
+
*/
|
|
10
|
+
export class ClientEventHandlers {
|
|
11
|
+
private readonly handlers_ = new Set<ClientEventHandler>()
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Register a handler
|
|
15
|
+
*
|
|
16
|
+
* @param handler
|
|
17
|
+
* @returns a function which removes the handler
|
|
18
|
+
*/
|
|
19
|
+
add(handler: ClientEventHandler): () => void {
|
|
20
|
+
this.handlers_.add(handler)
|
|
21
|
+
return () => this.remove(handler)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
remove(handler: ClientEventHandler): void {
|
|
25
|
+
this.handlers_.delete(handler)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Call every handler with the event data, a handler
|
|
30
|
+
* which throws does not stop the others
|
|
31
|
+
*
|
|
32
|
+
* @param data
|
|
33
|
+
*/
|
|
34
|
+
dispatch(data: any): void {
|
|
35
|
+
for (const handler of [...this.handlers_]) {
|
|
36
|
+
try {
|
|
37
|
+
handler(data)
|
|
38
|
+
} catch (err) {
|
|
39
|
+
log.error(`Event handler failed`, err)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
package/src/common/index.ts
CHANGED
package/src/common/types.ts
CHANGED
|
@@ -78,6 +78,12 @@ export interface PendingRequestMessage<
|
|
|
78
78
|
*/
|
|
79
79
|
export type EventHandler = (clientId: string, port: Port, payload: any) => boolean
|
|
80
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Handles an event pushed by the `utilityProcess`
|
|
83
|
+
* to a client (`UPMNodeProcess.sendEvent`)
|
|
84
|
+
*/
|
|
85
|
+
export type ClientEventHandler = (data: any) => void
|
|
86
|
+
|
|
81
87
|
/**
|
|
82
88
|
* Port of any kind
|
|
83
89
|
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
app, MessageChannelMain, MessagePortMain, utilityProcess, UtilityProcess
|
|
3
3
|
} from "electron"
|
|
4
|
-
import { assert, getValue, isNumber, isString } from "@3fv/guard"
|
|
4
|
+
import { assert, getValue, isDefined, isNumber, isString } from "@3fv/guard"
|
|
5
5
|
import Fs from "fs"
|
|
6
6
|
import { Deferred } from "@3fv/deferred"
|
|
7
7
|
import * as UPM from "../common/index.js"
|
|
@@ -12,7 +12,7 @@ import Tracer from "tracer"
|
|
|
12
12
|
import { asOption } from "@3fv/prelude-ts"
|
|
13
13
|
import { match } from "ts-pattern"
|
|
14
14
|
|
|
15
|
-
const log = Tracer.colorConsole()
|
|
15
|
+
const log = Tracer.colorConsole({ level: "info" })
|
|
16
16
|
const isNotEmpty = negate(isEmpty)
|
|
17
17
|
|
|
18
18
|
/**
|
|
@@ -46,6 +46,26 @@ export class UPMMainService<ReqMap extends UPM.MessageRequestMap = any, MType ex
|
|
|
46
46
|
port.postMessage(payload)
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Register a handler for events the service pushes to
|
|
51
|
+
* the main process (`UPMNodeProcess.sendEvent`)
|
|
52
|
+
*
|
|
53
|
+
* @param handler
|
|
54
|
+
* @returns a function which removes the handler
|
|
55
|
+
*/
|
|
56
|
+
addEventHandler(handler:UPM.ClientEventHandler):() => void {
|
|
57
|
+
return this.eventHandlers_.add(handler)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Remove a handler registered with `addEventHandler`
|
|
62
|
+
*
|
|
63
|
+
* @param handler
|
|
64
|
+
*/
|
|
65
|
+
removeEventHandler(handler:UPM.ClientEventHandler):void {
|
|
66
|
+
this.eventHandlers_.remove(handler)
|
|
67
|
+
}
|
|
68
|
+
|
|
49
69
|
/**
|
|
50
70
|
* Send request
|
|
51
71
|
*
|
|
@@ -130,6 +150,8 @@ export class UPMMainService<ReqMap extends UPM.MessageRequestMap = any, MType ex
|
|
|
130
150
|
|
|
131
151
|
private pendingMessages_ = new Map<number, UPM.PendingRequestMessage>()
|
|
132
152
|
|
|
153
|
+
private eventHandlers_ = new UPM.ClientEventHandlers()
|
|
154
|
+
|
|
133
155
|
private messageChannels_ = new Map<string, MessageChannelMain>()
|
|
134
156
|
|
|
135
157
|
private onServiceExit(code:number) {
|
|
@@ -271,20 +293,30 @@ export class UPMMainService<ReqMap extends UPM.MessageRequestMap = any, MType ex
|
|
|
271
293
|
}
|
|
272
294
|
|
|
273
295
|
/**
|
|
274
|
-
*
|
|
275
|
-
* `executeRequest(...)
|
|
276
|
-
*
|
|
296
|
+
* Handles what the service posts on its parent port:
|
|
297
|
+
* `results` of `executeRequest(...)` & events pushed
|
|
298
|
+
* with `UPMNodeProcess.sendEvent(...)`
|
|
277
299
|
*
|
|
278
|
-
* @param
|
|
300
|
+
* @param payloadOrEnvelope the service posts a `NodeEnvelope`
|
|
279
301
|
* @private
|
|
280
302
|
*/
|
|
281
|
-
private onMessage<Type extends MType = any>(
|
|
282
|
-
const
|
|
303
|
+
private onMessage<Type extends MType = any>(payloadOrEnvelope:UPM.Message<ReqMap, Type> | UPM.NodeMessage<ReqMap, Type>) {
|
|
304
|
+
const payload = (
|
|
305
|
+
isDefined(payloadOrEnvelope?.["payload"]) ? payloadOrEnvelope["payload"] : payloadOrEnvelope
|
|
306
|
+
) as UPM.Message<ReqMap, Type>,
|
|
307
|
+
{ messageId, result, error } = payload
|
|
308
|
+
|
|
309
|
+
// EVENT PUSHED BY THE SERVICE
|
|
310
|
+
if (payload?.kind === UPM.MessageKind.Event) {
|
|
311
|
+
log.debug(`Event received from service (${this.serviceName},messageId=${messageId})`)
|
|
312
|
+
this.eventHandlers_.dispatch(payload.eventData)
|
|
313
|
+
return
|
|
314
|
+
}
|
|
283
315
|
|
|
284
316
|
try {
|
|
285
317
|
const pending = this.pendingMessages_.get(messageId)
|
|
286
318
|
if (!pending) {
|
|
287
|
-
log.
|
|
319
|
+
log.debug(`Unable to find pending record ${messageId}`)
|
|
288
320
|
return
|
|
289
321
|
}
|
|
290
322
|
|
|
@@ -4,7 +4,13 @@ import * as UPM from "../common/index.js"
|
|
|
4
4
|
import Tracer from "tracer"
|
|
5
5
|
import { Future } from "@3fv/prelude-ts"
|
|
6
6
|
|
|
7
|
-
const log = Tracer.colorConsole()
|
|
7
|
+
const log = Tracer.colorConsole({ level: "info" })
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* `clientId` of the main process, which is
|
|
11
|
+
* reached through `process.parentPort`
|
|
12
|
+
*/
|
|
13
|
+
export const MainClientId = "main"
|
|
8
14
|
|
|
9
15
|
export class UPMNodeProcess
|
|
10
16
|
{
|
|
@@ -16,16 +22,26 @@ export class UPMNodeProcess
|
|
|
16
22
|
|
|
17
23
|
private readonly eventHandlers_ = Array<UPM.EventHandler>()
|
|
18
24
|
|
|
25
|
+
private messageIdSeq_ = 0
|
|
26
|
+
|
|
19
27
|
private onServiceClientPort(clientId: string, port: Electron.MessagePortMain) {
|
|
20
28
|
log.info(`Received new client port for clientId (${clientId})`)
|
|
21
|
-
|
|
29
|
+
|
|
30
|
+
// A CLIENT WHICH RECONNECTS (i.e. A RELOADED RENDERER) REPLACES ITS PORT
|
|
31
|
+
const existingPort = this.clientPorts_.get(clientId)
|
|
32
|
+
if (existingPort) {
|
|
33
|
+
log.warn(`Replacing the port registered for clientId (${clientId})`)
|
|
34
|
+
this.clientPorts_.delete(clientId)
|
|
35
|
+
existingPort.close()
|
|
36
|
+
}
|
|
37
|
+
this.clientPorts_.set(clientId, port)
|
|
22
38
|
|
|
23
39
|
port.on("message", (ev: Electron.MessageEvent) => {
|
|
24
40
|
const envelope = (
|
|
25
41
|
ev.data?.message ?? ev.data
|
|
26
42
|
) as UPM.NodeEnvelope,
|
|
27
43
|
{ channel, payload } = envelope
|
|
28
|
-
log.
|
|
44
|
+
log.debug(`Message received on client port (${clientId})`, envelope)
|
|
29
45
|
|
|
30
46
|
assert(
|
|
31
47
|
channel === UPM.IPCChannel.UPMServiceMessage,
|
|
@@ -36,14 +52,16 @@ export class UPMNodeProcess
|
|
|
36
52
|
})
|
|
37
53
|
|
|
38
54
|
port.on("close", () => {
|
|
39
|
-
this.clientPorts_.
|
|
55
|
+
if (this.clientPorts_.get(clientId) === port) {
|
|
56
|
+
this.clientPorts_.delete(clientId)
|
|
57
|
+
}
|
|
40
58
|
})
|
|
41
59
|
|
|
42
60
|
port.start()
|
|
43
61
|
}
|
|
44
62
|
|
|
45
63
|
private async onServiceMessage(clientId: string, port: UPM.Port, payload: UPM.Message<any, any>) {
|
|
46
|
-
log.
|
|
64
|
+
log.debug(`onServiceMessage from (clientId=${clientId})`, payload)
|
|
47
65
|
const { messageId, kind, args, eventData, type } = payload
|
|
48
66
|
await match(kind)
|
|
49
67
|
.with(UPM.MessageKind.Request, async () => {
|
|
@@ -92,7 +110,7 @@ export class UPMNodeProcess
|
|
|
92
110
|
}
|
|
93
111
|
|
|
94
112
|
if (res === true) {
|
|
95
|
-
log.
|
|
113
|
+
log.debug(`Successfully handled (${messageId}) event`)
|
|
96
114
|
return
|
|
97
115
|
}
|
|
98
116
|
}
|
|
@@ -107,12 +125,12 @@ export class UPMNodeProcess
|
|
|
107
125
|
}
|
|
108
126
|
|
|
109
127
|
private onMessage(port: UPM.Port, message: Electron.MessageEvent) {
|
|
110
|
-
log.
|
|
128
|
+
log.debug(`Message received on utilityProcess`, message.data)
|
|
111
129
|
const { channel, payload } = (
|
|
112
130
|
message.data?.message ?? message.data
|
|
113
131
|
) as UPM.NodeEnvelope
|
|
114
132
|
match(channel)
|
|
115
|
-
.when(c => c === UPM.IPCChannel.UPMServiceMessage, () => this.onServiceMessage(
|
|
133
|
+
.when(c => c === UPM.IPCChannel.UPMServiceMessage, () => this.onServiceMessage(MainClientId, port, payload))
|
|
116
134
|
.when(
|
|
117
135
|
c => c === UPM.IPCChannel.UPMServiceNewClient,
|
|
118
136
|
() => this.onServiceClientPort(payload.clientId, message.ports[0])
|
|
@@ -140,6 +158,53 @@ export class UPMNodeProcess
|
|
|
140
158
|
this.eventHandlers_.push(handler)
|
|
141
159
|
}
|
|
142
160
|
|
|
161
|
+
/**
|
|
162
|
+
* The `clientId` of every client which can currently
|
|
163
|
+
* be pushed an event: the main process (`MainClientId`)
|
|
164
|
+
* and each client with an open port
|
|
165
|
+
*/
|
|
166
|
+
get clientIds(): string[] {
|
|
167
|
+
return [MainClientId, ...this.clientPorts_.keys()]
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Push an event from the `utilityProcess` to its clients
|
|
172
|
+
* as `fire-and-forget`; a client receives it through
|
|
173
|
+
* the handlers it registered with `addEventHandler`.
|
|
174
|
+
*
|
|
175
|
+
* @param data any structured-cloneable value
|
|
176
|
+
* @param clientIds the clients to push to, every client
|
|
177
|
+
* (the main process included) when none are given
|
|
178
|
+
* @returns the `clientId` of each client the event was posted to
|
|
179
|
+
*/
|
|
180
|
+
sendEvent(data: any, ...clientIds: string[]): string[] {
|
|
181
|
+
const messageId = this.messageIdSeq_++,
|
|
182
|
+
envelope: UPM.NodeEnvelope = {
|
|
183
|
+
channel: UPM.IPCChannel.UPMServiceMessage,
|
|
184
|
+
payload: { messageId, eventData: data, kind: UPM.MessageKind.Event }
|
|
185
|
+
},
|
|
186
|
+
targetIds = clientIds.length ? [...new Set(clientIds)] : this.clientIds,
|
|
187
|
+
sentIds = Array<string>()
|
|
188
|
+
|
|
189
|
+
for (const clientId of targetIds) {
|
|
190
|
+
const port = clientId === MainClientId ? this.processPort : this.clientPorts_.get(clientId)
|
|
191
|
+
if (!port) {
|
|
192
|
+
log.warn(`Unable to send event (${messageId}), no port for clientId (${clientId})`)
|
|
193
|
+
continue
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
try {
|
|
197
|
+
port.postMessage(envelope)
|
|
198
|
+
sentIds.push(clientId)
|
|
199
|
+
} catch (err) {
|
|
200
|
+
log.error(`Unable to send event (${messageId}) to clientId (${clientId})`, err)
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
log.debug(`Sent event (${messageId}) to clients`, sentIds)
|
|
205
|
+
return sentIds
|
|
206
|
+
}
|
|
207
|
+
|
|
143
208
|
/**
|
|
144
209
|
* Singleton instance
|
|
145
210
|
*
|