@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 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
- process.on('message', handleMessage);
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
- const abort = DelightRPC.createAbort(request.id, channel);
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
- pendings.delete(request.id);
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
- process.off('message', handleMessage);
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 handleMessage(res) {
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
- process.on('message', handleMessage);
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
- const abort = DelightRPC.createAbort(request.id, channel);
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
- pendings.delete(request.id);
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
- process.off('message', handleMessage);
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 handleMessage(res) {
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":"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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
@@ -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
- process.on('message', handleMessage);
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
- return () => {
10
- process.off('message', handleMessage);
11
- process.off('disconnect', abortAllPendings);
12
- abortAllPendings();
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 handleMessage(message) {
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
- channelIdToController.delete(message);
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;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.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
- const abort = DelightRPC.createAbort(request.id, channel)
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
- pendings.delete(request.id)
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
- process.off('message', handleMessage)
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 handleMessage(res: unknown): void {
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 pendings: Map<
83
- string
84
- , Deferred<IError | IBatchResponse<unknown>>
85
- > = new Map()
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 res = new Deferred<
93
- | IError
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
- const abort = DelightRPC.createAbort(request.id, channel)
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
- pendings.delete(request.id)
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
- process.off('message', handleMessage)
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 handleMessage(res: unknown): void {
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
- return () => {
28
- process.off('message', handleMessage)
29
- process.off('disconnect', abortAllPendings)
30
- abortAllPendings()
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 handleMessage(message: unknown): Promise<void> {
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
- channelIdToController.delete(message)
91
+ destructor.execute()
73
92
  }
74
93
  } else if (DelightRPC.isAbort(message)) {
75
94
  if (DelightRPC.matchChannel(message, channel)) {