@grest-ts/ipc 0.0.5 → 0.0.7
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/LICENSE +21 -21
- package/README.md +5 -0
- package/dist/tsconfig.publish.tsbuildinfo +1 -1
- package/package.json +7 -7
- package/src/client/IPCClient.ts +99 -99
- package/src/common/IPCSocket.ts +251 -251
- package/src/common/IPCTypes.ts +17 -17
- package/src/index-node.ts +6 -6
- package/src/server/HttpHandler.ts +107 -107
- package/src/server/IPCServer.ts +159 -159
- package/src/server/SocketHandler.ts +146 -146
package/src/common/IPCSocket.ts
CHANGED
|
@@ -1,251 +1,251 @@
|
|
|
1
|
-
import WebSocket from 'ws';
|
|
2
|
-
import {GGLog} from "@grest-ts/logger";
|
|
3
|
-
import {GGLocator} from "@grest-ts/locator";
|
|
4
|
-
|
|
5
|
-
export enum IPCMessageType {
|
|
6
|
-
MSG = 'm',
|
|
7
|
-
REQ = 'r',
|
|
8
|
-
RES = 's'
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface IPCMessage {
|
|
12
|
-
type: IPCMessageType;
|
|
13
|
-
id: string;
|
|
14
|
-
path: string;
|
|
15
|
-
data?: unknown;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export type IPCMessageHandler = (data: unknown) => void | Promise<void>;
|
|
19
|
-
export type IPCRequestHandler = (data: unknown) => Promise<unknown>;
|
|
20
|
-
|
|
21
|
-
interface PendingRequest {
|
|
22
|
-
resolve: (data: unknown) => void;
|
|
23
|
-
reject: (error: Error) => void;
|
|
24
|
-
timeout: NodeJS.Timeout;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export class IPCSocket {
|
|
28
|
-
|
|
29
|
-
private readonly ws: WebSocket;
|
|
30
|
-
private readonly messageHandlers: Map<string, IPCMessageHandler> = new Map();
|
|
31
|
-
private readonly requestHandlers: Map<string, IPCRequestHandler> = new Map();
|
|
32
|
-
private readonly pendingRequests: Map<string, PendingRequest> = new Map();
|
|
33
|
-
|
|
34
|
-
private requestIdCounter = 0;
|
|
35
|
-
private active = true;
|
|
36
|
-
|
|
37
|
-
private readonly closeCallbacks: Array<() => void> = [];
|
|
38
|
-
private readonly errorCallbacks: Array<(error: Error) => void> = [];
|
|
39
|
-
|
|
40
|
-
constructor(ws: WebSocket) {
|
|
41
|
-
this.ws = ws;
|
|
42
|
-
const scope = GGLocator.getScope();
|
|
43
|
-
|
|
44
|
-
ws.on('message', async (data: Buffer) => {
|
|
45
|
-
scope.ensureEntered();
|
|
46
|
-
await this.handleRawMessage(data.toString('utf8'));
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
ws.on('close', () => {
|
|
50
|
-
scope.ensureEntered();
|
|
51
|
-
this.active = false;
|
|
52
|
-
for (const pending of this.pendingRequests.values()) {
|
|
53
|
-
clearTimeout(pending.timeout);
|
|
54
|
-
pending.reject(new Error('Connection closed'));
|
|
55
|
-
}
|
|
56
|
-
this.pendingRequests.clear();
|
|
57
|
-
this.closeCallbacks.forEach(cb => {
|
|
58
|
-
try {
|
|
59
|
-
cb();
|
|
60
|
-
} catch (e) { /* ignore */
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
ws.on('error', (error: Error) => {
|
|
66
|
-
scope.ensureEntered();
|
|
67
|
-
this.errorCallbacks.forEach(cb => {
|
|
68
|
-
try {
|
|
69
|
-
cb(error);
|
|
70
|
-
} catch (e) { /* ignore */
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
private static DELIMITER = ':';
|
|
77
|
-
|
|
78
|
-
private static serialize(msg: IPCMessage): string {
|
|
79
|
-
const dataStr = msg.data !== undefined ? JSON.stringify(msg.data) : '';
|
|
80
|
-
return `${msg.type}${this.DELIMITER}${msg.id}${this.DELIMITER}${msg.path}${this.DELIMITER}${dataStr}`;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
private static parse(raw: string): IPCMessage | undefined {
|
|
84
|
-
const parts = raw.split(this.DELIMITER);
|
|
85
|
-
if (parts.length < 3) return undefined;
|
|
86
|
-
|
|
87
|
-
const type = parts[0] as IPCMessageType;
|
|
88
|
-
const id = parts[1];
|
|
89
|
-
const path = parts[2];
|
|
90
|
-
const dataStr = parts.length > 3 ? parts.slice(3).join(this.DELIMITER) : '';
|
|
91
|
-
|
|
92
|
-
let data: unknown;
|
|
93
|
-
if (dataStr) {
|
|
94
|
-
try {
|
|
95
|
-
data = JSON.parse(dataStr);
|
|
96
|
-
} catch {
|
|
97
|
-
// Invalid JSON
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return {type, id, path, data};
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
private async handleRawMessage(raw: string): Promise<void> {
|
|
105
|
-
const msg = IPCSocket.parse(raw);
|
|
106
|
-
if (!msg) {
|
|
107
|
-
GGLog.warn(this, `Invalid IPC message: ${raw.substring(0, 100)}`);
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
switch (msg.type) {
|
|
112
|
-
case IPCMessageType.MSG:
|
|
113
|
-
await this.handleIncomingMessage(msg);
|
|
114
|
-
break;
|
|
115
|
-
case IPCMessageType.REQ:
|
|
116
|
-
await this.handleIncomingRequest(msg);
|
|
117
|
-
break;
|
|
118
|
-
case IPCMessageType.RES:
|
|
119
|
-
this.handleIncomingResponse(msg);
|
|
120
|
-
break;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
private async handleIncomingMessage(msg: IPCMessage): Promise<void> {
|
|
125
|
-
const handler = this.messageHandlers.get(msg.path);
|
|
126
|
-
if (!handler) {
|
|
127
|
-
GGLog.debug(this, `No handler for message: ${msg.path}`);
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
try {
|
|
131
|
-
await handler(msg.data);
|
|
132
|
-
} catch (error) {
|
|
133
|
-
GGLog.error(this, `Message handler error for ${msg.path}`, error);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
private async handleIncomingRequest(msg: IPCMessage): Promise<void> {
|
|
138
|
-
const handler = this.requestHandlers.get(msg.path);
|
|
139
|
-
|
|
140
|
-
const sendResponse = (success: boolean, data?: unknown, error?: string) => {
|
|
141
|
-
if (this.ws.readyState === WebSocket.OPEN) {
|
|
142
|
-
const response: IPCMessage = {
|
|
143
|
-
type: IPCMessageType.RES,
|
|
144
|
-
id: msg.id,
|
|
145
|
-
path: msg.path,
|
|
146
|
-
data: {success, data, error}
|
|
147
|
-
};
|
|
148
|
-
this.ws.send(IPCSocket.serialize(response));
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
if (!handler) {
|
|
153
|
-
sendResponse(false, undefined, `No handler for: ${msg.path}`);
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
try {
|
|
158
|
-
const result = await handler(msg.data);
|
|
159
|
-
sendResponse(true, result);
|
|
160
|
-
} catch (error: any) {
|
|
161
|
-
GGLog.error(this, `Request handler error for ${msg.path}`, error);
|
|
162
|
-
sendResponse(false, undefined, error.message || String(error));
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
private handleIncomingResponse(msg: IPCMessage): void {
|
|
167
|
-
const pending = this.pendingRequests.get(msg.id);
|
|
168
|
-
if (!pending) {
|
|
169
|
-
GGLog.debug(this, `No pending request for response id: ${msg.id}`);
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
clearTimeout(pending.timeout);
|
|
174
|
-
this.pendingRequests.delete(msg.id);
|
|
175
|
-
|
|
176
|
-
const response = msg.data as { success: boolean; data?: unknown; error?: string };
|
|
177
|
-
if (response.success) {
|
|
178
|
-
pending.resolve(response.data);
|
|
179
|
-
} else {
|
|
180
|
-
pending.reject(new Error(response.error || 'Request failed'));
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
public onMessage(path: string, handler: IPCMessageHandler): void {
|
|
185
|
-
this.messageHandlers.set(path, handler);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
public onRequest(path: string, handler: IPCRequestHandler): void {
|
|
189
|
-
this.requestHandlers.set(path, handler);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
public onClose(callback: () => void): void {
|
|
193
|
-
this.closeCallbacks.push(callback);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
public onError(callback: (error: Error) => void): void {
|
|
197
|
-
this.errorCallbacks.push(callback);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
public send(path: string, data?: unknown): void {
|
|
201
|
-
if (!this.active || this.ws.readyState !== WebSocket.OPEN) {
|
|
202
|
-
throw new Error('Socket not connected');
|
|
203
|
-
}
|
|
204
|
-
const msg: IPCMessage = {type: IPCMessageType.MSG, id: '', path, data};
|
|
205
|
-
this.ws.send(IPCSocket.serialize(msg));
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
public async request<T = unknown>(path: string, data?: unknown, timeoutMs: number = 10000): Promise<T> {
|
|
209
|
-
if (!this.active || this.ws.readyState !== WebSocket.OPEN) {
|
|
210
|
-
throw new Error('Socket not connected');
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
const id = `${++this.requestIdCounter}`;
|
|
214
|
-
const msg: IPCMessage = {type: IPCMessageType.REQ, id, path, data};
|
|
215
|
-
|
|
216
|
-
return new Promise<T>((resolve, reject) => {
|
|
217
|
-
const timeout = setTimeout(() => {
|
|
218
|
-
this.pendingRequests.delete(id);
|
|
219
|
-
reject(new Error(`Request '${path}' timed out after ${timeoutMs}ms`));
|
|
220
|
-
}, timeoutMs);
|
|
221
|
-
|
|
222
|
-
this.pendingRequests.set(id, {
|
|
223
|
-
resolve: resolve as (data: unknown) => void,
|
|
224
|
-
reject,
|
|
225
|
-
timeout
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
this.ws.send(IPCSocket.serialize(msg));
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
public isConnected(): boolean {
|
|
233
|
-
return this.active && this.ws.readyState === WebSocket.OPEN;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
public close(): void {
|
|
237
|
-
if (this.active) {
|
|
238
|
-
this.active = false;
|
|
239
|
-
this.ws.terminate();
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
public teardown(): void {
|
|
244
|
-
for (const pending of this.pendingRequests.values()) {
|
|
245
|
-
clearTimeout(pending.timeout);
|
|
246
|
-
pending.reject(new Error('Socket teardown'));
|
|
247
|
-
}
|
|
248
|
-
this.pendingRequests.clear();
|
|
249
|
-
this.close();
|
|
250
|
-
}
|
|
251
|
-
}
|
|
1
|
+
import WebSocket from 'ws';
|
|
2
|
+
import {GGLog} from "@grest-ts/logger";
|
|
3
|
+
import {GGLocator} from "@grest-ts/locator";
|
|
4
|
+
|
|
5
|
+
export enum IPCMessageType {
|
|
6
|
+
MSG = 'm',
|
|
7
|
+
REQ = 'r',
|
|
8
|
+
RES = 's'
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface IPCMessage {
|
|
12
|
+
type: IPCMessageType;
|
|
13
|
+
id: string;
|
|
14
|
+
path: string;
|
|
15
|
+
data?: unknown;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type IPCMessageHandler = (data: unknown) => void | Promise<void>;
|
|
19
|
+
export type IPCRequestHandler = (data: unknown) => Promise<unknown>;
|
|
20
|
+
|
|
21
|
+
interface PendingRequest {
|
|
22
|
+
resolve: (data: unknown) => void;
|
|
23
|
+
reject: (error: Error) => void;
|
|
24
|
+
timeout: NodeJS.Timeout;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class IPCSocket {
|
|
28
|
+
|
|
29
|
+
private readonly ws: WebSocket;
|
|
30
|
+
private readonly messageHandlers: Map<string, IPCMessageHandler> = new Map();
|
|
31
|
+
private readonly requestHandlers: Map<string, IPCRequestHandler> = new Map();
|
|
32
|
+
private readonly pendingRequests: Map<string, PendingRequest> = new Map();
|
|
33
|
+
|
|
34
|
+
private requestIdCounter = 0;
|
|
35
|
+
private active = true;
|
|
36
|
+
|
|
37
|
+
private readonly closeCallbacks: Array<() => void> = [];
|
|
38
|
+
private readonly errorCallbacks: Array<(error: Error) => void> = [];
|
|
39
|
+
|
|
40
|
+
constructor(ws: WebSocket) {
|
|
41
|
+
this.ws = ws;
|
|
42
|
+
const scope = GGLocator.getScope();
|
|
43
|
+
|
|
44
|
+
ws.on('message', async (data: Buffer) => {
|
|
45
|
+
scope.ensureEntered();
|
|
46
|
+
await this.handleRawMessage(data.toString('utf8'));
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
ws.on('close', () => {
|
|
50
|
+
scope.ensureEntered();
|
|
51
|
+
this.active = false;
|
|
52
|
+
for (const pending of this.pendingRequests.values()) {
|
|
53
|
+
clearTimeout(pending.timeout);
|
|
54
|
+
pending.reject(new Error('Connection closed'));
|
|
55
|
+
}
|
|
56
|
+
this.pendingRequests.clear();
|
|
57
|
+
this.closeCallbacks.forEach(cb => {
|
|
58
|
+
try {
|
|
59
|
+
cb();
|
|
60
|
+
} catch (e) { /* ignore */
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
ws.on('error', (error: Error) => {
|
|
66
|
+
scope.ensureEntered();
|
|
67
|
+
this.errorCallbacks.forEach(cb => {
|
|
68
|
+
try {
|
|
69
|
+
cb(error);
|
|
70
|
+
} catch (e) { /* ignore */
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private static DELIMITER = ':';
|
|
77
|
+
|
|
78
|
+
private static serialize(msg: IPCMessage): string {
|
|
79
|
+
const dataStr = msg.data !== undefined ? JSON.stringify(msg.data) : '';
|
|
80
|
+
return `${msg.type}${this.DELIMITER}${msg.id}${this.DELIMITER}${msg.path}${this.DELIMITER}${dataStr}`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private static parse(raw: string): IPCMessage | undefined {
|
|
84
|
+
const parts = raw.split(this.DELIMITER);
|
|
85
|
+
if (parts.length < 3) return undefined;
|
|
86
|
+
|
|
87
|
+
const type = parts[0] as IPCMessageType;
|
|
88
|
+
const id = parts[1];
|
|
89
|
+
const path = parts[2];
|
|
90
|
+
const dataStr = parts.length > 3 ? parts.slice(3).join(this.DELIMITER) : '';
|
|
91
|
+
|
|
92
|
+
let data: unknown;
|
|
93
|
+
if (dataStr) {
|
|
94
|
+
try {
|
|
95
|
+
data = JSON.parse(dataStr);
|
|
96
|
+
} catch {
|
|
97
|
+
// Invalid JSON
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return {type, id, path, data};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private async handleRawMessage(raw: string): Promise<void> {
|
|
105
|
+
const msg = IPCSocket.parse(raw);
|
|
106
|
+
if (!msg) {
|
|
107
|
+
GGLog.warn(this, `Invalid IPC message: ${raw.substring(0, 100)}`);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
switch (msg.type) {
|
|
112
|
+
case IPCMessageType.MSG:
|
|
113
|
+
await this.handleIncomingMessage(msg);
|
|
114
|
+
break;
|
|
115
|
+
case IPCMessageType.REQ:
|
|
116
|
+
await this.handleIncomingRequest(msg);
|
|
117
|
+
break;
|
|
118
|
+
case IPCMessageType.RES:
|
|
119
|
+
this.handleIncomingResponse(msg);
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
private async handleIncomingMessage(msg: IPCMessage): Promise<void> {
|
|
125
|
+
const handler = this.messageHandlers.get(msg.path);
|
|
126
|
+
if (!handler) {
|
|
127
|
+
GGLog.debug(this, `No handler for message: ${msg.path}`);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
await handler(msg.data);
|
|
132
|
+
} catch (error) {
|
|
133
|
+
GGLog.error(this, `Message handler error for ${msg.path}`, error);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
private async handleIncomingRequest(msg: IPCMessage): Promise<void> {
|
|
138
|
+
const handler = this.requestHandlers.get(msg.path);
|
|
139
|
+
|
|
140
|
+
const sendResponse = (success: boolean, data?: unknown, error?: string) => {
|
|
141
|
+
if (this.ws.readyState === WebSocket.OPEN) {
|
|
142
|
+
const response: IPCMessage = {
|
|
143
|
+
type: IPCMessageType.RES,
|
|
144
|
+
id: msg.id,
|
|
145
|
+
path: msg.path,
|
|
146
|
+
data: {success, data, error}
|
|
147
|
+
};
|
|
148
|
+
this.ws.send(IPCSocket.serialize(response));
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
if (!handler) {
|
|
153
|
+
sendResponse(false, undefined, `No handler for: ${msg.path}`);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
try {
|
|
158
|
+
const result = await handler(msg.data);
|
|
159
|
+
sendResponse(true, result);
|
|
160
|
+
} catch (error: any) {
|
|
161
|
+
GGLog.error(this, `Request handler error for ${msg.path}`, error);
|
|
162
|
+
sendResponse(false, undefined, error.message || String(error));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
private handleIncomingResponse(msg: IPCMessage): void {
|
|
167
|
+
const pending = this.pendingRequests.get(msg.id);
|
|
168
|
+
if (!pending) {
|
|
169
|
+
GGLog.debug(this, `No pending request for response id: ${msg.id}`);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
clearTimeout(pending.timeout);
|
|
174
|
+
this.pendingRequests.delete(msg.id);
|
|
175
|
+
|
|
176
|
+
const response = msg.data as { success: boolean; data?: unknown; error?: string };
|
|
177
|
+
if (response.success) {
|
|
178
|
+
pending.resolve(response.data);
|
|
179
|
+
} else {
|
|
180
|
+
pending.reject(new Error(response.error || 'Request failed'));
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
public onMessage(path: string, handler: IPCMessageHandler): void {
|
|
185
|
+
this.messageHandlers.set(path, handler);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
public onRequest(path: string, handler: IPCRequestHandler): void {
|
|
189
|
+
this.requestHandlers.set(path, handler);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
public onClose(callback: () => void): void {
|
|
193
|
+
this.closeCallbacks.push(callback);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
public onError(callback: (error: Error) => void): void {
|
|
197
|
+
this.errorCallbacks.push(callback);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
public send(path: string, data?: unknown): void {
|
|
201
|
+
if (!this.active || this.ws.readyState !== WebSocket.OPEN) {
|
|
202
|
+
throw new Error('Socket not connected');
|
|
203
|
+
}
|
|
204
|
+
const msg: IPCMessage = {type: IPCMessageType.MSG, id: '', path, data};
|
|
205
|
+
this.ws.send(IPCSocket.serialize(msg));
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
public async request<T = unknown>(path: string, data?: unknown, timeoutMs: number = 10000): Promise<T> {
|
|
209
|
+
if (!this.active || this.ws.readyState !== WebSocket.OPEN) {
|
|
210
|
+
throw new Error('Socket not connected');
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const id = `${++this.requestIdCounter}`;
|
|
214
|
+
const msg: IPCMessage = {type: IPCMessageType.REQ, id, path, data};
|
|
215
|
+
|
|
216
|
+
return new Promise<T>((resolve, reject) => {
|
|
217
|
+
const timeout = setTimeout(() => {
|
|
218
|
+
this.pendingRequests.delete(id);
|
|
219
|
+
reject(new Error(`Request '${path}' timed out after ${timeoutMs}ms`));
|
|
220
|
+
}, timeoutMs);
|
|
221
|
+
|
|
222
|
+
this.pendingRequests.set(id, {
|
|
223
|
+
resolve: resolve as (data: unknown) => void,
|
|
224
|
+
reject,
|
|
225
|
+
timeout
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
this.ws.send(IPCSocket.serialize(msg));
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
public isConnected(): boolean {
|
|
233
|
+
return this.active && this.ws.readyState === WebSocket.OPEN;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
public close(): void {
|
|
237
|
+
if (this.active) {
|
|
238
|
+
this.active = false;
|
|
239
|
+
this.ws.terminate();
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
public teardown(): void {
|
|
244
|
+
for (const pending of this.pendingRequests.values()) {
|
|
245
|
+
clearTimeout(pending.timeout);
|
|
246
|
+
pending.reject(new Error('Socket teardown'));
|
|
247
|
+
}
|
|
248
|
+
this.pendingRequests.clear();
|
|
249
|
+
this.close();
|
|
250
|
+
}
|
|
251
|
+
}
|
package/src/common/IPCTypes.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Type for messages that the IPC server handles (sent by client, handled by server)
|
|
3
|
-
*/
|
|
4
|
-
export type IPCServerRequest<Request, Response> = string & {
|
|
5
|
-
__IPCServerRequest: never;
|
|
6
|
-
__request: Request;
|
|
7
|
-
__response: Response;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Type for messages that the IPC client handles (sent by server, handled by client)
|
|
12
|
-
*/
|
|
13
|
-
export type IPCClientRequest<Request, Response> = string & {
|
|
14
|
-
__IPCClientRequest: never;
|
|
15
|
-
__request: Request;
|
|
16
|
-
__response: Response;
|
|
17
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Type for messages that the IPC server handles (sent by client, handled by server)
|
|
3
|
+
*/
|
|
4
|
+
export type IPCServerRequest<Request, Response> = string & {
|
|
5
|
+
__IPCServerRequest: never;
|
|
6
|
+
__request: Request;
|
|
7
|
+
__response: Response;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Type for messages that the IPC client handles (sent by server, handled by client)
|
|
12
|
+
*/
|
|
13
|
+
export type IPCClientRequest<Request, Response> = string & {
|
|
14
|
+
__IPCClientRequest: never;
|
|
15
|
+
__request: Request;
|
|
16
|
+
__response: Response;
|
|
17
|
+
}
|
package/src/index-node.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export * from './server/IPCServer'
|
|
2
|
-
export * from './client/IPCClient'
|
|
3
|
-
export * from './common/IPCSocket'
|
|
4
|
-
export * from './common/IPCTypes'
|
|
5
|
-
export {INTERNAL_SOCKET_PATH} from './server/SocketHandler'
|
|
6
|
-
export type {SocketMessage} from './server/SocketHandler'
|
|
1
|
+
export * from './server/IPCServer'
|
|
2
|
+
export * from './client/IPCClient'
|
|
3
|
+
export * from './common/IPCSocket'
|
|
4
|
+
export * from './common/IPCTypes'
|
|
5
|
+
export {INTERNAL_SOCKET_PATH} from './server/SocketHandler'
|
|
6
|
+
export type {SocketMessage} from './server/SocketHandler'
|