@delight-rpc/child-process 0.7.2 → 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 CHANGED
@@ -3,46 +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
- process.on('message', handleMessage);
10
+ destructor.defer(abortAllPendings);
11
+ process.on('message', receive);
12
+ destructor.defer(() => process.off('message', receive));
9
13
  process.on('disconnect', abortAllPendings);
14
+ destructor.defer(() => process.off('disconnect', abortAllPendings));
10
15
  const client = DelightRPC.createClient(async function send(request, signal) {
16
+ const destructor = new SyncDestructor();
11
17
  const res = new Deferred();
12
18
  pendings.set(request.id, res);
19
+ destructor.defer(() => pendings.delete(request.id));
13
20
  try {
14
21
  process.send(request);
15
22
  const mergedSignal = raceAbortSignals([
16
23
  isntUndefined(timeout) && timeoutSignal(timeout),
17
24
  signal
18
25
  ]);
19
- mergedSignal.addEventListener('abort', () => {
20
- const abort = DelightRPC.createAbort(request.id, channel);
21
- process.send(abort);
22
- });
26
+ mergedSignal.addEventListener('abort', sendAbort);
27
+ destructor.defer(() => mergedSignal.removeEventListener('abort', sendAbort));
23
28
  return await withAbortSignal(mergedSignal, () => res);
24
29
  }
25
30
  finally {
26
- pendings.delete(request.id);
31
+ destructor.execute();
32
+ }
33
+ function sendAbort() {
34
+ const abort = DelightRPC.createAbort(request.id, channel);
35
+ process.send(abort);
27
36
  }
28
37
  }, {
29
38
  parameterValidators,
30
39
  expectedVersion,
31
40
  channel
32
41
  });
33
- return [client, close];
34
- function close() {
35
- process.off('message', handleMessage);
36
- process.off('disconnect', abortAllPendings);
37
- abortAllPendings();
38
- }
42
+ return [client, () => destructor.execute()];
39
43
  function abortAllPendings() {
40
44
  for (const deferred of pendings.values()) {
41
45
  deferred.reject(new ClientClosed());
42
46
  }
43
47
  pendings.clear();
44
48
  }
45
- function handleMessage(res) {
49
+ function receive(res) {
46
50
  var _a;
47
51
  if (DelightRPC.isResult(res) || DelightRPC.isError(res)) {
48
52
  (_a = pendings.get(res.id)) === null || _a === void 0 ? void 0 : _a.resolve(res);
@@ -50,43 +54,46 @@ export function createClient(process, { parameterValidators, expectedVersion, ch
50
54
  }
51
55
  }
52
56
  export function createBatchClient(process, { expectedVersion, channel, timeout } = {}) {
57
+ const destructor = new SyncDestructor();
53
58
  const pendings = new Map();
54
- process.on('message', handleMessage);
59
+ destructor.defer(abortAllPendings);
60
+ process.on('message', receive);
61
+ destructor.defer(() => process.off('message', receive));
55
62
  process.on('disconnect', abortAllPendings);
63
+ destructor.defer(() => process.off('disconnect', abortAllPendings));
56
64
  const client = new DelightRPC.BatchClient(async function send(request) {
65
+ const destructor = new SyncDestructor();
57
66
  const res = new Deferred();
58
67
  pendings.set(request.id, res);
68
+ destructor.defer(() => pendings.delete(request.id));
59
69
  try {
60
70
  process.send(request);
61
71
  const mergedSignal = raceAbortSignals([
62
72
  isntUndefined(timeout) && timeoutSignal(timeout)
63
73
  ]);
64
- mergedSignal.addEventListener('abort', () => {
65
- const abort = DelightRPC.createAbort(request.id, channel);
66
- process.send(abort);
67
- });
74
+ mergedSignal.addEventListener('abort', sendAbort);
75
+ destructor.defer(() => mergedSignal.removeEventListener('abort', sendAbort));
68
76
  return await withAbortSignal(mergedSignal, () => res);
69
77
  }
70
78
  finally {
71
- pendings.delete(request.id);
79
+ destructor.execute();
80
+ }
81
+ function sendAbort() {
82
+ const abort = DelightRPC.createAbort(request.id, channel);
83
+ process.send(abort);
72
84
  }
73
85
  }, {
74
86
  expectedVersion,
75
87
  channel
76
88
  });
77
- return [client, close];
78
- function close() {
79
- process.off('message', handleMessage);
80
- process.off('disconnect', abortAllPendings);
81
- abortAllPendings();
82
- }
89
+ return [client, () => destructor.execute()];
83
90
  function abortAllPendings() {
84
91
  for (const deferred of pendings.values()) {
85
92
  deferred.reject(new ClientClosed());
86
93
  }
87
94
  pendings.clear();
88
95
  }
89
- function handleMessage(res) {
96
+ function receive(res) {
90
97
  var _a;
91
98
  if (DelightRPC.isError(res) || DelightRPC.isBatchResponse(res)) {
92
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":"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"}
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
- process.on('message', handleMessage);
9
+ destructor.defer(abortAllPendings);
10
+ process.on('message', receive);
11
+ destructor.defer(() => process.off('message', receive));
8
12
  process.on('disconnect', abortAllPendings);
9
- return () => {
10
- process.off('message', handleMessage);
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 handleMessage(message) {
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
- channelIdToController.delete(message);
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;AAEhD,MAAM,UAAU,YAAY,CAC1B,GAAsC,EACtC,OAAsC,EACtC,EAAE,mBAAmB,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,KAKjD,EAAE;IAEN,MAAM,qBAAqB,GAMvB,IAAI,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,CAAA;IAEnE,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,aAAa,CAAC,CAAA;IACpC,OAAO,CAAC,EAAE,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAA;IAC1C,OAAO,GAAG,EAAE;QACV,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,aAAa,CAAC,CAAA;QACrC,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAA;QAC3C,gBAAgB,EAAE,CAAA;IACpB,CAAC,CAAA;IAED,SAAS,gBAAgB;QACvB,KAAK,MAAM,UAAU,IAAI,qBAAqB,CAAC,MAAM,EAAE,EAAE,CAAC;YACxD,UAAU,CAAC,KAAK,EAAE,CAAA;QACpB,CAAC;QAED,qBAAqB,CAAC,KAAK,EAAE,CAAA;IAC/B,CAAC;IAED,KAAK,UAAU,aAAa,CAAC,OAAgB;;QAC3C,IAAI,UAAU,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,UAAU,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC;YACxE,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;YACxC,qBAAqB,CAAC,GAAG,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;YAE9C,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,cAAc,CAC5C,GAAG,EACH,OAAO,EACP;oBACE,mBAAmB;oBACnB,OAAO;oBACP,OAAO;oBACP,YAAY;oBACZ,MAAM,EAAE,UAAU,CAAC,MAAM;iBAC1B,CACF,CAAA;gBAED,IAAI,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;oBAErB,OAAO,CAAC,IAAK,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE;wBAC1B,IAAI,GAAG,EAAE,CAAC;4BACR,IAAK,GAA6B,CAAC,IAAI,KAAK,wBAAwB,EAAE,CAAC;gCACrE,IAAI,EAAE,CAAA;4BACR,CAAC;iCAAM,CAAC;gCACN,MAAM,GAAG,CAAA;4BACX,CAAC;wBACH,CAAC;oBACH,CAAC,CAAC,CAAA;gBACJ,CAAC;YACH,CAAC;oBAAS,CAAC;gBACT,qBAAqB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;YACvC,CAAC;QACH,CAAC;aAAM,IAAI,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YACvC,IAAI,UAAU,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;gBAC9C,MAAA,qBAAqB,CAAC,GAAG,CAAC,OAAO,CAAC,0CAAE,KAAK,EAAE,CAAA;gBAC3C,qBAAqB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;YACvC,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC"}
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.2",
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,15 +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('message', handleMessage)
21
27
  process.on('disconnect', abortAllPendings)
28
+ destructor.defer(() => process.off('disconnect', abortAllPendings))
22
29
 
23
30
  const client = DelightRPC.createClient<IAPI>(
24
31
  async function send(request, signal) {
32
+ const destructor = new SyncDestructor()
33
+
25
34
  const res = new Deferred<IResponse<unknown>>()
26
35
  pendings.set(request.id, res)
36
+ destructor.defer(() => pendings.delete(request.id))
37
+
27
38
  try {
28
39
  process.send!(request)
29
40
 
@@ -31,14 +42,17 @@ export function createClient<IAPI extends object>(
31
42
  isntUndefined(timeout) && timeoutSignal(timeout)
32
43
  , signal
33
44
  ])
34
- mergedSignal.addEventListener('abort', () => {
35
- const abort = DelightRPC.createAbort(request.id, channel)
36
- process.send!(abort)
37
- })
45
+ mergedSignal.addEventListener('abort', sendAbort)
46
+ destructor.defer(() => mergedSignal.removeEventListener('abort', sendAbort))
38
47
 
39
48
  return await withAbortSignal(mergedSignal, () => res)
40
49
  } finally {
41
- pendings.delete(request.id)
50
+ destructor.execute()
51
+ }
52
+
53
+ function sendAbort(): void {
54
+ const abort = DelightRPC.createAbort(request.id, channel)
55
+ process.send!(abort)
42
56
  }
43
57
  }
44
58
  , {
@@ -48,13 +62,7 @@ export function createClient<IAPI extends object>(
48
62
  }
49
63
  )
50
64
 
51
- return [client, close]
52
-
53
- function close(): void {
54
- process.off('message', handleMessage)
55
- process.off('disconnect', abortAllPendings)
56
- abortAllPendings()
57
- }
65
+ return [client, () => destructor.execute()]
58
66
 
59
67
  function abortAllPendings(): void {
60
68
  for (const deferred of pendings.values()) {
@@ -64,7 +72,7 @@ export function createClient<IAPI extends object>(
64
72
  pendings.clear()
65
73
  }
66
74
 
67
- function handleMessage(res: unknown): void {
75
+ function receive(res: unknown): void {
68
76
  if (DelightRPC.isResult(res) || DelightRPC.isError(res)) {
69
77
  pendings.get(res.id)?.resolve(res)
70
78
  }
@@ -79,35 +87,42 @@ export function createBatchClient<DataType>(
79
87
  timeout?: number
80
88
  } = {}
81
89
  ): [client: DelightRPC.BatchClient<DataType>, close: () => void] {
82
- const pendings: Map<
83
- string
84
- , Deferred<IError | IBatchResponse<unknown>>
85
- > = new Map()
90
+ const destructor = new SyncDestructor()
91
+
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))
86
97
 
87
- process.on('message', handleMessage)
88
98
  process.on('disconnect', abortAllPendings)
99
+ destructor.defer(() => process.off('disconnect', abortAllPendings))
89
100
 
90
101
  const client = new DelightRPC.BatchClient(
91
102
  async function send(request: IBatchRequest<unknown>) {
92
- const res = new Deferred<
93
- | IError
94
- | IBatchResponse<unknown>
95
- >()
103
+ const destructor = new SyncDestructor()
104
+
105
+ const res = new Deferred<IError | IBatchResponse<unknown>>()
96
106
  pendings.set(request.id, res)
107
+ destructor.defer(() => pendings.delete(request.id))
108
+
97
109
  try {
98
110
  process.send!(request)
99
111
 
100
112
  const mergedSignal = raceAbortSignals([
101
113
  isntUndefined(timeout) && timeoutSignal(timeout)
102
114
  ])
103
- mergedSignal.addEventListener('abort', () => {
104
- const abort = DelightRPC.createAbort(request.id, channel)
105
- process.send!(abort)
106
- })
115
+ mergedSignal.addEventListener('abort', sendAbort)
116
+ destructor.defer(() => mergedSignal.removeEventListener('abort', sendAbort))
107
117
 
108
118
  return await withAbortSignal(mergedSignal, () => res)
109
119
  } finally {
110
- pendings.delete(request.id)
120
+ destructor.execute()
121
+ }
122
+
123
+ function sendAbort(): void {
124
+ const abort = DelightRPC.createAbort(request.id, channel)
125
+ process.send!(abort)
111
126
  }
112
127
  }
113
128
  , {
@@ -116,13 +131,7 @@ export function createBatchClient<DataType>(
116
131
  }
117
132
  )
118
133
 
119
- return [client, close]
120
-
121
- function close(): void {
122
- process.off('message', handleMessage)
123
- process.off('disconnect', abortAllPendings)
124
- abortAllPendings()
125
- }
134
+ return [client, () => destructor.execute()]
126
135
 
127
136
  function abortAllPendings(): void {
128
137
  for (const deferred of pendings.values()) {
@@ -132,7 +141,7 @@ export function createBatchClient<DataType>(
132
141
  pendings.clear()
133
142
  }
134
143
 
135
- function handleMessage(res: unknown): void {
144
+ function receive(res: unknown): void {
136
145
  if (DelightRPC.isError(res) || DelightRPC.isBatchResponse(res)) {
137
146
  pendings.get(res.id)?.resolve(res)
138
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
- return () => {
28
- process.off('message', handleMessage)
29
- process.off('disconnect', abortAllPendings)
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 handleMessage(message: unknown): Promise<void> {
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
- channelIdToController.delete(message)
79
+ destructor.execute()
73
80
  }
74
81
  } else if (DelightRPC.isAbort(message)) {
75
82
  if (DelightRPC.matchChannel(message, channel)) {