@delight-rpc/child-process 0.6.1 → 0.6.2

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/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@delight-rpc/child-process",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
4
4
  "description": "",
5
5
  "keywords": [],
6
6
  "files": [
7
- "lib"
7
+ "lib",
8
+ "src"
8
9
  ],
9
10
  "type": "module",
10
11
  "main": "lib/index.js",
@@ -37,7 +38,7 @@
37
38
  "@commitlint/cli": "^17.4.4",
38
39
  "@commitlint/config-conventional": "^17.4.4",
39
40
  "@types/jest": "^29.5.0",
40
- "@types/node": "14",
41
+ "@types/node": "16",
41
42
  "@typescript-eslint/eslint-plugin": "^5.55.0",
42
43
  "@typescript-eslint/parser": "^5.55.0",
43
44
  "cross-env": "^7.0.3",
package/src/client.ts ADDED
@@ -0,0 +1,108 @@
1
+ import * as DelightRPC from 'delight-rpc'
2
+ import { ChildProcess } from 'child_process'
3
+ import { Deferred } from 'extra-promise'
4
+ import { CustomError } from '@blackglory/errors'
5
+ import { IRequest, IResponse, IError, IBatchRequest, IBatchResponse } from '@delight-rpc/protocol'
6
+
7
+ export function createClient<IAPI extends object>(
8
+ process: ChildProcess | NodeJS.Process
9
+ , { parameterValidators, expectedVersion, channel }: {
10
+ parameterValidators?: DelightRPC.ParameterValidators<IAPI>
11
+ expectedVersion?: string
12
+ channel?: string
13
+ } = {}
14
+ ): [client: DelightRPC.ClientProxy<IAPI>, close: () => void] {
15
+ const pendings: Record<string, Deferred<IResponse<unknown>> | undefined> = {}
16
+
17
+ process.on('message', handler)
18
+
19
+ const client = DelightRPC.createClient<IAPI>(
20
+ async function send(request: IRequest<unknown>) {
21
+ const res = new Deferred<IResponse<unknown>>()
22
+ pendings[request.id] = res
23
+ try {
24
+ process.send!(request)
25
+ return await res
26
+ } finally {
27
+ delete pendings[request.id]
28
+ }
29
+ }
30
+ , {
31
+ parameterValidators
32
+ , expectedVersion
33
+ , channel
34
+ }
35
+ )
36
+
37
+ return [client, close]
38
+
39
+ function close() {
40
+ process.off('message', handler)
41
+
42
+ for (const [key, deferred] of Object.entries(pendings)) {
43
+ deferred!.reject(new ClientClosed())
44
+ delete pendings[key]
45
+ }
46
+ }
47
+
48
+ function handler(res: any): void {
49
+ if (DelightRPC.isResult(res) || DelightRPC.isError(res)) {
50
+ pendings[res.id]?.resolve(res)
51
+ }
52
+ }
53
+ }
54
+
55
+ export function createBatchClient<DataType>(
56
+ process: ChildProcess | NodeJS.Process
57
+ , { expectedVersion, channel }: {
58
+ expectedVersion?: string
59
+ channel?: string
60
+ } = {}
61
+ ): [client: DelightRPC.BatchClient<DataType>, close: () => void] {
62
+ const pendings: Record<
63
+ string
64
+ , | Deferred<IError | IBatchResponse<unknown>>
65
+ | undefined
66
+ > = {}
67
+
68
+ process.on('message', handler)
69
+
70
+ const client = new DelightRPC.BatchClient(
71
+ async function send(request: IBatchRequest<unknown>) {
72
+ const res = new Deferred<
73
+ | IError
74
+ | IBatchResponse<unknown>
75
+ >()
76
+ pendings[request.id] = res
77
+ try {
78
+ process.send!(request)
79
+ return await res
80
+ } finally {
81
+ delete pendings[request.id]
82
+ }
83
+ }
84
+ , {
85
+ expectedVersion
86
+ , channel
87
+ }
88
+ )
89
+
90
+ return [client, close]
91
+
92
+ function close() {
93
+ process.off('message', handler)
94
+
95
+ for (const [key, deferred] of Object.entries(pendings)) {
96
+ deferred!.reject(new ClientClosed())
97
+ delete pendings[key]
98
+ }
99
+ }
100
+
101
+ function handler(res: any): void {
102
+ if (DelightRPC.isError(res) || DelightRPC.isBatchResponse(res)) {
103
+ pendings[res.id]?.resolve(res)
104
+ }
105
+ }
106
+ }
107
+
108
+ export class ClientClosed extends CustomError {}
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from './client.js'
2
+ export * from './server.js'
package/src/server.ts ADDED
@@ -0,0 +1,36 @@
1
+ import * as DelightRPC from 'delight-rpc'
2
+ import { ChildProcess } from 'child_process'
3
+ import { isntNull } from '@blackglory/prelude'
4
+
5
+ export function createServer<IAPI extends object>(
6
+ api: DelightRPC.ImplementationOf<IAPI>
7
+ , process: ChildProcess | NodeJS.Process
8
+ , { parameterValidators, version, channel, ownPropsOnly }: {
9
+ parameterValidators?: DelightRPC.ParameterValidators<IAPI>
10
+ version?: `${number}.${number}.${number}`
11
+ channel?: string | RegExp | typeof DelightRPC.AnyChannel
12
+ ownPropsOnly?: boolean
13
+ } = {}
14
+ ): () => void {
15
+ process.on('message', handler)
16
+ return () => process.off('message', handler)
17
+
18
+ async function handler(req: any): Promise<void> {
19
+ if (DelightRPC.isRequest(req) || DelightRPC.isBatchRequest(req)) {
20
+ const result = await DelightRPC.createResponse(
21
+ api
22
+ , req
23
+ , {
24
+ parameterValidators
25
+ , version
26
+ , channel
27
+ , ownPropsOnly
28
+ }
29
+ )
30
+
31
+ if (isntNull(result)) {
32
+ process.send!(result)
33
+ }
34
+ }
35
+ }
36
+ }