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