@delight-rpc/child-process 0.7.1 → 0.7.3
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/lib/client.js +41 -24
- package/lib/client.js.map +1 -1
- package/lib/server.js +11 -8
- package/lib/server.js.map +1 -1
- package/package.json +2 -1
- package/src/client.ts +55 -34
- package/src/server.ts +15 -8
package/lib/client.js
CHANGED
|
@@ -3,41 +3,50 @@ import { Deferred } from 'extra-promise';
|
|
|
3
3
|
import { CustomError } from '@blackglory/errors';
|
|
4
4
|
import { raceAbortSignals, timeoutSignal, withAbortSignal } from 'extra-abort';
|
|
5
5
|
import { isntUndefined } from '@blackglory/prelude';
|
|
6
|
+
import { SyncDestructor } from 'extra-defer';
|
|
6
7
|
export function createClient(process, { parameterValidators, expectedVersion, channel, timeout } = {}) {
|
|
8
|
+
const destructor = new SyncDestructor();
|
|
7
9
|
const pendings = new Map();
|
|
8
|
-
|
|
10
|
+
destructor.defer(abortAllPendings);
|
|
11
|
+
process.on('message', receive);
|
|
12
|
+
destructor.defer(() => process.off('message', receive));
|
|
13
|
+
process.on('disconnect', abortAllPendings);
|
|
14
|
+
destructor.defer(() => process.off('disconnect', abortAllPendings));
|
|
9
15
|
const client = DelightRPC.createClient(async function send(request, signal) {
|
|
16
|
+
const destructor = new SyncDestructor();
|
|
10
17
|
const res = new Deferred();
|
|
11
18
|
pendings.set(request.id, res);
|
|
19
|
+
destructor.defer(() => pendings.delete(request.id));
|
|
12
20
|
try {
|
|
13
21
|
process.send(request);
|
|
14
22
|
const mergedSignal = raceAbortSignals([
|
|
15
23
|
isntUndefined(timeout) && timeoutSignal(timeout),
|
|
16
24
|
signal
|
|
17
25
|
]);
|
|
18
|
-
mergedSignal.addEventListener('abort',
|
|
19
|
-
|
|
20
|
-
process.send(abort);
|
|
21
|
-
});
|
|
26
|
+
mergedSignal.addEventListener('abort', sendAbort);
|
|
27
|
+
destructor.defer(() => mergedSignal.removeEventListener('abort', sendAbort));
|
|
22
28
|
return await withAbortSignal(mergedSignal, () => res);
|
|
23
29
|
}
|
|
24
30
|
finally {
|
|
25
|
-
|
|
31
|
+
destructor.execute();
|
|
32
|
+
}
|
|
33
|
+
function sendAbort() {
|
|
34
|
+
const abort = DelightRPC.createAbort(request.id, channel);
|
|
35
|
+
process.send(abort);
|
|
26
36
|
}
|
|
27
37
|
}, {
|
|
28
38
|
parameterValidators,
|
|
29
39
|
expectedVersion,
|
|
30
40
|
channel
|
|
31
41
|
});
|
|
32
|
-
return [client,
|
|
33
|
-
function
|
|
34
|
-
|
|
35
|
-
for (const [key, deferred] of pendings.entries()) {
|
|
42
|
+
return [client, () => destructor.execute()];
|
|
43
|
+
function abortAllPendings() {
|
|
44
|
+
for (const deferred of pendings.values()) {
|
|
36
45
|
deferred.reject(new ClientClosed());
|
|
37
|
-
pendings.delete(key);
|
|
38
46
|
}
|
|
47
|
+
pendings.clear();
|
|
39
48
|
}
|
|
40
|
-
function
|
|
49
|
+
function receive(res) {
|
|
41
50
|
var _a;
|
|
42
51
|
if (DelightRPC.isResult(res) || DelightRPC.isError(res)) {
|
|
43
52
|
(_a = pendings.get(res.id)) === null || _a === void 0 ? void 0 : _a.resolve(res);
|
|
@@ -45,38 +54,46 @@ export function createClient(process, { parameterValidators, expectedVersion, ch
|
|
|
45
54
|
}
|
|
46
55
|
}
|
|
47
56
|
export function createBatchClient(process, { expectedVersion, channel, timeout } = {}) {
|
|
57
|
+
const destructor = new SyncDestructor();
|
|
48
58
|
const pendings = new Map();
|
|
49
|
-
|
|
59
|
+
destructor.defer(abortAllPendings);
|
|
60
|
+
process.on('message', receive);
|
|
61
|
+
destructor.defer(() => process.off('message', receive));
|
|
62
|
+
process.on('disconnect', abortAllPendings);
|
|
63
|
+
destructor.defer(() => process.off('disconnect', abortAllPendings));
|
|
50
64
|
const client = new DelightRPC.BatchClient(async function send(request) {
|
|
65
|
+
const destructor = new SyncDestructor();
|
|
51
66
|
const res = new Deferred();
|
|
52
67
|
pendings.set(request.id, res);
|
|
68
|
+
destructor.defer(() => pendings.delete(request.id));
|
|
53
69
|
try {
|
|
54
70
|
process.send(request);
|
|
55
71
|
const mergedSignal = raceAbortSignals([
|
|
56
72
|
isntUndefined(timeout) && timeoutSignal(timeout)
|
|
57
73
|
]);
|
|
58
|
-
mergedSignal.addEventListener('abort',
|
|
59
|
-
|
|
60
|
-
process.send(abort);
|
|
61
|
-
});
|
|
74
|
+
mergedSignal.addEventListener('abort', sendAbort);
|
|
75
|
+
destructor.defer(() => mergedSignal.removeEventListener('abort', sendAbort));
|
|
62
76
|
return await withAbortSignal(mergedSignal, () => res);
|
|
63
77
|
}
|
|
64
78
|
finally {
|
|
65
|
-
|
|
79
|
+
destructor.execute();
|
|
80
|
+
}
|
|
81
|
+
function sendAbort() {
|
|
82
|
+
const abort = DelightRPC.createAbort(request.id, channel);
|
|
83
|
+
process.send(abort);
|
|
66
84
|
}
|
|
67
85
|
}, {
|
|
68
86
|
expectedVersion,
|
|
69
87
|
channel
|
|
70
88
|
});
|
|
71
|
-
return [client,
|
|
72
|
-
function
|
|
73
|
-
|
|
74
|
-
for (const [key, deferred] of pendings.entries()) {
|
|
89
|
+
return [client, () => destructor.execute()];
|
|
90
|
+
function abortAllPendings() {
|
|
91
|
+
for (const deferred of pendings.values()) {
|
|
75
92
|
deferred.reject(new ClientClosed());
|
|
76
|
-
pendings.delete(key);
|
|
77
93
|
}
|
|
94
|
+
pendings.clear();
|
|
78
95
|
}
|
|
79
|
-
function
|
|
96
|
+
function receive(res) {
|
|
80
97
|
var _a;
|
|
81
98
|
if (DelightRPC.isError(res) || DelightRPC.isBatchResponse(res)) {
|
|
82
99
|
(_a = pendings.get(res.id)) === null || _a === void 0 ? void 0 : _a.resolve(res);
|
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,aAAa,CAAA;AAEzC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAEhD,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC9E,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/lib/server.js
CHANGED
|
@@ -2,26 +2,29 @@ import * as DelightRPC from 'delight-rpc';
|
|
|
2
2
|
import { isntNull, pass } from '@blackglory/prelude';
|
|
3
3
|
import { AbortController } from 'extra-abort';
|
|
4
4
|
import { HashMap } from '@blackglory/structures';
|
|
5
|
+
import { SyncDestructor } from 'extra-defer';
|
|
5
6
|
export function createServer(api, process, { parameterValidators, version, channel, ownPropsOnly } = {}) {
|
|
7
|
+
const destructor = new SyncDestructor();
|
|
6
8
|
const channelIdToController = new HashMap(({ channel, id }) => JSON.stringify([channel, id]));
|
|
7
|
-
|
|
9
|
+
destructor.defer(abortAllPendings);
|
|
10
|
+
process.on('message', receive);
|
|
11
|
+
destructor.defer(() => process.off('message', receive));
|
|
8
12
|
process.on('disconnect', abortAllPendings);
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
process.off('disconnect', abortAllPendings);
|
|
12
|
-
abortAllPendings();
|
|
13
|
-
};
|
|
13
|
+
destructor.defer(() => process.off('disconnect', abortAllPendings));
|
|
14
|
+
return () => destructor.execute();
|
|
14
15
|
function abortAllPendings() {
|
|
15
16
|
for (const controller of channelIdToController.values()) {
|
|
16
17
|
controller.abort();
|
|
17
18
|
}
|
|
18
19
|
channelIdToController.clear();
|
|
19
20
|
}
|
|
20
|
-
async function
|
|
21
|
+
async function receive(message) {
|
|
21
22
|
var _a;
|
|
22
23
|
if (DelightRPC.isRequest(message) || DelightRPC.isBatchRequest(message)) {
|
|
24
|
+
const destructor = new SyncDestructor();
|
|
23
25
|
const controller = new AbortController();
|
|
24
26
|
channelIdToController.set(message, controller);
|
|
27
|
+
destructor.defer(() => channelIdToController.delete(message));
|
|
25
28
|
try {
|
|
26
29
|
const result = await DelightRPC.createResponse(api, message, {
|
|
27
30
|
parameterValidators,
|
|
@@ -44,7 +47,7 @@ export function createServer(api, process, { parameterValidators, version, chann
|
|
|
44
47
|
}
|
|
45
48
|
}
|
|
46
49
|
finally {
|
|
47
|
-
|
|
50
|
+
destructor.execute();
|
|
48
51
|
}
|
|
49
52
|
}
|
|
50
53
|
else if (DelightRPC.isAbort(message)) {
|
package/lib/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,aAAa,CAAA;AAEzC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@delight-rpc/child-process",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.3",
|
|
4
4
|
"description": "",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"files": [
|
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
"@blackglory/structures": "^0.14.13",
|
|
59
59
|
"@delight-rpc/protocol": "^4.0.0",
|
|
60
60
|
"extra-abort": "^0.4.1",
|
|
61
|
+
"extra-defer": "^0.3.1",
|
|
61
62
|
"extra-promise": "^7.1.1"
|
|
62
63
|
},
|
|
63
64
|
"peerDependencies": {
|
package/src/client.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { CustomError } from '@blackglory/errors'
|
|
|
5
5
|
import { IResponse, IError, IBatchRequest, IBatchResponse } from '@delight-rpc/protocol'
|
|
6
6
|
import { raceAbortSignals, timeoutSignal, withAbortSignal } from 'extra-abort'
|
|
7
7
|
import { isntUndefined } from '@blackglory/prelude'
|
|
8
|
+
import { SyncDestructor } from 'extra-defer'
|
|
8
9
|
|
|
9
10
|
export function createClient<IAPI extends object>(
|
|
10
11
|
process: ChildProcess | NodeJS.Process
|
|
@@ -15,14 +16,25 @@ export function createClient<IAPI extends object>(
|
|
|
15
16
|
timeout?: number
|
|
16
17
|
} = {}
|
|
17
18
|
): [client: DelightRPC.ClientProxy<IAPI>, close: () => void] {
|
|
19
|
+
const destructor = new SyncDestructor()
|
|
20
|
+
|
|
18
21
|
const pendings: Map<string, Deferred<IResponse<unknown>>> = new Map()
|
|
22
|
+
destructor.defer(abortAllPendings)
|
|
23
|
+
|
|
24
|
+
process.on('message', receive)
|
|
25
|
+
destructor.defer(() => process.off('message', receive))
|
|
19
26
|
|
|
20
|
-
process.on('
|
|
27
|
+
process.on('disconnect', abortAllPendings)
|
|
28
|
+
destructor.defer(() => process.off('disconnect', abortAllPendings))
|
|
21
29
|
|
|
22
30
|
const client = DelightRPC.createClient<IAPI>(
|
|
23
31
|
async function send(request, signal) {
|
|
32
|
+
const destructor = new SyncDestructor()
|
|
33
|
+
|
|
24
34
|
const res = new Deferred<IResponse<unknown>>()
|
|
25
35
|
pendings.set(request.id, res)
|
|
36
|
+
destructor.defer(() => pendings.delete(request.id))
|
|
37
|
+
|
|
26
38
|
try {
|
|
27
39
|
process.send!(request)
|
|
28
40
|
|
|
@@ -30,14 +42,17 @@ export function createClient<IAPI extends object>(
|
|
|
30
42
|
isntUndefined(timeout) && timeoutSignal(timeout)
|
|
31
43
|
, signal
|
|
32
44
|
])
|
|
33
|
-
mergedSignal.addEventListener('abort',
|
|
34
|
-
|
|
35
|
-
process.send!(abort)
|
|
36
|
-
})
|
|
45
|
+
mergedSignal.addEventListener('abort', sendAbort)
|
|
46
|
+
destructor.defer(() => mergedSignal.removeEventListener('abort', sendAbort))
|
|
37
47
|
|
|
38
48
|
return await withAbortSignal(mergedSignal, () => res)
|
|
39
49
|
} finally {
|
|
40
|
-
|
|
50
|
+
destructor.execute()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function sendAbort(): void {
|
|
54
|
+
const abort = DelightRPC.createAbort(request.id, channel)
|
|
55
|
+
process.send!(abort)
|
|
41
56
|
}
|
|
42
57
|
}
|
|
43
58
|
, {
|
|
@@ -47,18 +62,17 @@ export function createClient<IAPI extends object>(
|
|
|
47
62
|
}
|
|
48
63
|
)
|
|
49
64
|
|
|
50
|
-
return [client,
|
|
65
|
+
return [client, () => destructor.execute()]
|
|
51
66
|
|
|
52
|
-
function
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
for (const [key, deferred] of pendings.entries()) {
|
|
67
|
+
function abortAllPendings(): void {
|
|
68
|
+
for (const deferred of pendings.values()) {
|
|
56
69
|
deferred.reject(new ClientClosed())
|
|
57
|
-
pendings.delete(key)
|
|
58
70
|
}
|
|
71
|
+
|
|
72
|
+
pendings.clear()
|
|
59
73
|
}
|
|
60
74
|
|
|
61
|
-
function
|
|
75
|
+
function receive(res: unknown): void {
|
|
62
76
|
if (DelightRPC.isResult(res) || DelightRPC.isError(res)) {
|
|
63
77
|
pendings.get(res.id)?.resolve(res)
|
|
64
78
|
}
|
|
@@ -73,34 +87,42 @@ export function createBatchClient<DataType>(
|
|
|
73
87
|
timeout?: number
|
|
74
88
|
} = {}
|
|
75
89
|
): [client: DelightRPC.BatchClient<DataType>, close: () => void] {
|
|
76
|
-
const
|
|
77
|
-
string
|
|
78
|
-
, Deferred<IError | IBatchResponse<unknown>>
|
|
79
|
-
> = new Map()
|
|
90
|
+
const destructor = new SyncDestructor()
|
|
80
91
|
|
|
81
|
-
|
|
92
|
+
const pendings: Map<string, Deferred<IError | IBatchResponse<unknown>>> = new Map()
|
|
93
|
+
destructor.defer(abortAllPendings)
|
|
94
|
+
|
|
95
|
+
process.on('message', receive)
|
|
96
|
+
destructor.defer(() => process.off('message', receive))
|
|
97
|
+
|
|
98
|
+
process.on('disconnect', abortAllPendings)
|
|
99
|
+
destructor.defer(() => process.off('disconnect', abortAllPendings))
|
|
82
100
|
|
|
83
101
|
const client = new DelightRPC.BatchClient(
|
|
84
102
|
async function send(request: IBatchRequest<unknown>) {
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
| IBatchResponse<unknown
|
|
88
|
-
>()
|
|
103
|
+
const destructor = new SyncDestructor()
|
|
104
|
+
|
|
105
|
+
const res = new Deferred<IError | IBatchResponse<unknown>>()
|
|
89
106
|
pendings.set(request.id, res)
|
|
107
|
+
destructor.defer(() => pendings.delete(request.id))
|
|
108
|
+
|
|
90
109
|
try {
|
|
91
110
|
process.send!(request)
|
|
92
111
|
|
|
93
112
|
const mergedSignal = raceAbortSignals([
|
|
94
113
|
isntUndefined(timeout) && timeoutSignal(timeout)
|
|
95
114
|
])
|
|
96
|
-
mergedSignal.addEventListener('abort',
|
|
97
|
-
|
|
98
|
-
process.send!(abort)
|
|
99
|
-
})
|
|
115
|
+
mergedSignal.addEventListener('abort', sendAbort)
|
|
116
|
+
destructor.defer(() => mergedSignal.removeEventListener('abort', sendAbort))
|
|
100
117
|
|
|
101
118
|
return await withAbortSignal(mergedSignal, () => res)
|
|
102
119
|
} finally {
|
|
103
|
-
|
|
120
|
+
destructor.execute()
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function sendAbort(): void {
|
|
124
|
+
const abort = DelightRPC.createAbort(request.id, channel)
|
|
125
|
+
process.send!(abort)
|
|
104
126
|
}
|
|
105
127
|
}
|
|
106
128
|
, {
|
|
@@ -109,18 +131,17 @@ export function createBatchClient<DataType>(
|
|
|
109
131
|
}
|
|
110
132
|
)
|
|
111
133
|
|
|
112
|
-
return [client,
|
|
134
|
+
return [client, () => destructor.execute()]
|
|
113
135
|
|
|
114
|
-
function
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
for (const [key, deferred] of pendings.entries()) {
|
|
136
|
+
function abortAllPendings(): void {
|
|
137
|
+
for (const deferred of pendings.values()) {
|
|
118
138
|
deferred.reject(new ClientClosed())
|
|
119
|
-
pendings.delete(key)
|
|
120
139
|
}
|
|
140
|
+
|
|
141
|
+
pendings.clear()
|
|
121
142
|
}
|
|
122
143
|
|
|
123
|
-
function
|
|
144
|
+
function receive(res: unknown): void {
|
|
124
145
|
if (DelightRPC.isError(res) || DelightRPC.isBatchResponse(res)) {
|
|
125
146
|
pendings.get(res.id)?.resolve(res)
|
|
126
147
|
}
|
package/src/server.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { ChildProcess } from 'child_process'
|
|
|
3
3
|
import { isntNull, pass } from '@blackglory/prelude'
|
|
4
4
|
import { AbortController } from 'extra-abort'
|
|
5
5
|
import { HashMap } from '@blackglory/structures'
|
|
6
|
+
import { SyncDestructor } from 'extra-defer'
|
|
6
7
|
|
|
7
8
|
export function createServer<IAPI extends object>(
|
|
8
9
|
api: DelightRPC.ImplementationOf<IAPI>
|
|
@@ -14,6 +15,8 @@ export function createServer<IAPI extends object>(
|
|
|
14
15
|
ownPropsOnly?: boolean
|
|
15
16
|
} = {}
|
|
16
17
|
): () => void {
|
|
18
|
+
const destructor = new SyncDestructor()
|
|
19
|
+
|
|
17
20
|
const channelIdToController: HashMap<
|
|
18
21
|
{
|
|
19
22
|
channel?: string
|
|
@@ -21,14 +24,15 @@ export function createServer<IAPI extends object>(
|
|
|
21
24
|
}
|
|
22
25
|
, AbortController
|
|
23
26
|
> = new HashMap(({ channel, id }) => JSON.stringify([channel, id]))
|
|
27
|
+
destructor.defer(abortAllPendings)
|
|
28
|
+
|
|
29
|
+
process.on('message', receive)
|
|
30
|
+
destructor.defer(() => process.off('message', receive))
|
|
24
31
|
|
|
25
|
-
process.on('message', handleMessage)
|
|
26
32
|
process.on('disconnect', abortAllPendings)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
abortAllPendings()
|
|
31
|
-
}
|
|
33
|
+
destructor.defer(() => process.off('disconnect', abortAllPendings))
|
|
34
|
+
|
|
35
|
+
return () => destructor.execute()
|
|
32
36
|
|
|
33
37
|
function abortAllPendings(): void {
|
|
34
38
|
for (const controller of channelIdToController.values()) {
|
|
@@ -38,10 +42,13 @@ export function createServer<IAPI extends object>(
|
|
|
38
42
|
channelIdToController.clear()
|
|
39
43
|
}
|
|
40
44
|
|
|
41
|
-
async function
|
|
45
|
+
async function receive(message: unknown): Promise<void> {
|
|
42
46
|
if (DelightRPC.isRequest(message) || DelightRPC.isBatchRequest(message)) {
|
|
47
|
+
const destructor = new SyncDestructor()
|
|
48
|
+
|
|
43
49
|
const controller = new AbortController()
|
|
44
50
|
channelIdToController.set(message, controller)
|
|
51
|
+
destructor.defer(() => channelIdToController.delete(message))
|
|
45
52
|
|
|
46
53
|
try {
|
|
47
54
|
const result = await DelightRPC.createResponse(
|
|
@@ -69,7 +76,7 @@ export function createServer<IAPI extends object>(
|
|
|
69
76
|
})
|
|
70
77
|
}
|
|
71
78
|
} finally {
|
|
72
|
-
|
|
79
|
+
destructor.execute()
|
|
73
80
|
}
|
|
74
81
|
} else if (DelightRPC.isAbort(message)) {
|
|
75
82
|
if (DelightRPC.matchChannel(message, channel)) {
|