@delight-rpc/child-process 0.6.0 → 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 +6 -6
- package/src/client.ts +108 -0
- package/src/index.ts +2 -0
- package/src/server.ts +36 -0
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@delight-rpc/child-process",
|
|
3
|
-
"version": "0.6.
|
|
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",
|
|
@@ -19,9 +20,8 @@
|
|
|
19
20
|
"scripts": {
|
|
20
21
|
"prepare": "ts-patch install -s",
|
|
21
22
|
"lint": "eslint --ext .js,.jsx,.ts,.tsx --quiet src",
|
|
22
|
-
"test": "cross-env NODE_OPTIONS='--experimental-vm-modules --loader ts-node/esm' jest --config jest.config.cjs",
|
|
23
|
+
"test": "cross-env NODE_OPTIONS='--experimental-vm-modules --loader ts-node/esm' jest --runInBand --config jest.config.cjs",
|
|
23
24
|
"test:debug": "cross-env NODE_OPTIONS='--experimental-vm-modules --loader ts-node/esm' node --inspect-brk node_modules/.bin/jest --runInBand --config jest.config.cjs",
|
|
24
|
-
"test:coverage": "cross-env NODE_OPTIONS='--experimental-vm-modules --loader ts-node/esm' jest --coverage --config jest.config.cjs",
|
|
25
25
|
"prepublishOnly": "run-s prepare clean build",
|
|
26
26
|
"clean": "rimraf lib",
|
|
27
27
|
"build": "tsc --project tsconfig.build.json",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"@commitlint/cli": "^17.4.4",
|
|
39
39
|
"@commitlint/config-conventional": "^17.4.4",
|
|
40
40
|
"@types/jest": "^29.5.0",
|
|
41
|
-
"@types/node": "
|
|
41
|
+
"@types/node": "16",
|
|
42
42
|
"@typescript-eslint/eslint-plugin": "^5.55.0",
|
|
43
43
|
"@typescript-eslint/parser": "^5.55.0",
|
|
44
44
|
"cross-env": "^7.0.3",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"dependencies": {
|
|
61
61
|
"@blackglory/errors": "^3.0.0",
|
|
62
62
|
"@blackglory/prelude": "^0.3.1",
|
|
63
|
-
"@delight-rpc/protocol": "^
|
|
63
|
+
"@delight-rpc/protocol": "^4.0.0",
|
|
64
64
|
"extra-promise": "^6.0.5"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
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
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
|
+
}
|