@x-oasis/async-call-rpc-misc 0.1.38
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/README.md +13 -0
- package/dist/async-call-rpc-misc.cjs.development.js +221 -0
- package/dist/async-call-rpc-misc.cjs.development.js.map +1 -0
- package/dist/async-call-rpc-misc.cjs.production.min.js +2 -0
- package/dist/async-call-rpc-misc.cjs.production.min.js.map +1 -0
- package/dist/async-call-rpc-misc.esm.js +216 -0
- package/dist/async-call-rpc-misc.esm.js.map +1 -0
- package/dist/buffer/DataBuffer.d.ts +2 -0
- package/dist/buffer/ReadBuffer.d.ts +12 -0
- package/dist/buffer/WriteBuffer.d.ts +3 -0
- package/dist/buffer/index.d.ts +3 -0
- package/dist/channel-protocol/AbstractChannelProtocol.d.ts +51 -0
- package/dist/channel-protocol/Channel.d.ts +16 -0
- package/dist/channel-protocol/DeferredMessageChannelProtocol.d.ts +8 -0
- package/dist/channel-protocol/IPCMainChannelProtocol.d.ts +7 -0
- package/dist/channel-protocol/IPCMainGlobalChannelProtocol.d.ts +7 -0
- package/dist/channel-protocol/IPCRendererChannelProtocol.d.ts +8 -0
- package/dist/channel-protocol/IPCRendererMessageChannelProtocol.d.ts +8 -0
- package/dist/channel-protocol/MessageChannelProtocol.d.ts +7 -0
- package/dist/channel-protocol/ProcessChannelProtocol.d.ts +7 -0
- package/dist/channel-protocol/ProcessClientChannelProtocol.d.ts +7 -0
- package/dist/channel-protocol/middlewares/buffer.d.ts +18 -0
- package/dist/channel-protocol/middlewares/handleDisconnectedRequest.d.ts +7 -0
- package/dist/channel-protocol/middlewares/handlePortRequest.d.ts +3 -0
- package/dist/channel-protocol/middlewares/handleRequest.d.ts +3 -0
- package/dist/channel-protocol/middlewares/handleRequestUtils.d.ts +10 -0
- package/dist/channel-protocol/middlewares/handleResponse.d.ts +3 -0
- package/dist/channel-protocol/middlewares/index.d.ts +10 -0
- package/dist/channel-protocol/middlewares/logger.d.ts +4 -0
- package/dist/channel-protocol/middlewares/normalize.d.ts +12 -0
- package/dist/channel-protocol/middlewares/prepareRequestData.d.ts +28 -0
- package/dist/channel-protocol/middlewares/sendRequest.d.ts +6 -0
- package/dist/channel-protocol/middlewares/updateSeqInfo.d.ts +6 -0
- package/dist/channel-protocol/middlewares/utils.d.ts +3 -0
- package/dist/common.d.ts +4 -0
- package/dist/error.d.ts +12 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +8 -0
- package/dist/rpc-service/ProxyRPCClient.d.ts +9 -0
- package/dist/rpc-service/RPCServiceHost.d.ts +11 -0
- package/dist/rpc-service/RPCServiceProvider.d.ts +9 -0
- package/dist/types/buffer.d.ts +4 -0
- package/dist/types/channel.d.ts +12 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/messageChannel.d.ts +76 -0
- package/dist/types/middleware.d.ts +44 -0
- package/dist/types/proxyChannel.d.ts +3 -0
- package/dist/types/proxyService.d.ts +10 -0
- package/dist/types/rpc.d.ts +31 -0
- package/dist/types/rpcProtocol.d.ts +22 -0
- package/package.json +38 -0
- package/src/buffer/DataBuffer.ts +1 -0
- package/src/buffer/ReadBuffer.ts +41 -0
- package/src/buffer/WriteBuffer.ts +5 -0
- package/src/buffer/index.ts +3 -0
- package/src/channel-protocol/AbstractChannelProtocol.ts +204 -0
- package/src/channel-protocol/Channel.ts +37 -0
- package/src/channel-protocol/DeferredMessageChannelProtocol.ts +85 -0
- package/src/channel-protocol/IPCMainChannelProtocol.ts +65 -0
- package/src/channel-protocol/IPCMainGlobalChannelProtocol.ts +66 -0
- package/src/channel-protocol/IPCRendererChannelProtocol.ts +81 -0
- package/src/channel-protocol/IPCRendererMessageChannelProtocol.ts +79 -0
- package/src/channel-protocol/MessageChannelProtocol.ts +63 -0
- package/src/channel-protocol/ProcessChannelProtocol.ts +60 -0
- package/src/channel-protocol/ProcessClientChannelProtocol.ts +59 -0
- package/src/channel-protocol/middlewares/buffer.ts +33 -0
- package/src/channel-protocol/middlewares/handleDisconnectedRequest.ts +30 -0
- package/src/channel-protocol/middlewares/handlePortRequest.ts +118 -0
- package/src/channel-protocol/middlewares/handleRequest.ts +163 -0
- package/src/channel-protocol/middlewares/handleRequestUtils.ts +42 -0
- package/src/channel-protocol/middlewares/handleResponse.ts +38 -0
- package/src/channel-protocol/middlewares/index.ts +11 -0
- package/src/channel-protocol/middlewares/logger.ts +22 -0
- package/src/channel-protocol/middlewares/normalize.ts +28 -0
- package/src/channel-protocol/middlewares/prepareRequestData.ts +137 -0
- package/src/channel-protocol/middlewares/sendRequest.ts +15 -0
- package/src/channel-protocol/middlewares/updateSeqInfo.ts +27 -0
- package/src/channel-protocol/middlewares/utils.ts +67 -0
- package/src/common.ts +20 -0
- package/src/error.ts +32 -0
- package/src/index.ts +5 -0
- package/src/rpc-service/ProxyRPCClient.ts +82 -0
- package/src/rpc-service/RPCServiceHost.ts +35 -0
- package/src/rpc-service/RPCServiceProvider.ts +22 -0
- package/src/types/buffer.ts +5 -0
- package/src/types/channel.ts +24 -0
- package/src/types/index.ts +6 -0
- package/src/types/messageChannel.ts +134 -0
- package/src/types/middleware.ts +53 -0
- package/src/types/proxyChannel.ts +3 -0
- package/src/types/proxyService.ts +16 -0
- package/src/types/rpc.ts +61 -0
- package/src/types/rpcProtocol.ts +24 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import AbstractChannelProtocol from '../AbstractChannelProtocol';
|
|
2
|
+
import {
|
|
3
|
+
SendingProps,
|
|
4
|
+
RequestEntryHeader,
|
|
5
|
+
HostRequestEntryHeader,
|
|
6
|
+
RequestType,
|
|
7
|
+
SendMiddlewareLifecycle,
|
|
8
|
+
} from '../../types';
|
|
9
|
+
|
|
10
|
+
export const preparePortData = (channel: AbstractChannelProtocol) => {
|
|
11
|
+
const fn = (props: string | SendingProps, ...args: any[]) => {
|
|
12
|
+
let requestPath = '';
|
|
13
|
+
let fnName = '';
|
|
14
|
+
let params = [] as any[];
|
|
15
|
+
let transfer = [];
|
|
16
|
+
let isOptionsRequest = false;
|
|
17
|
+
|
|
18
|
+
const seqId = channel.seqId;
|
|
19
|
+
|
|
20
|
+
if (typeof props === 'string') {
|
|
21
|
+
requestPath = props;
|
|
22
|
+
fnName = args[0];
|
|
23
|
+
params = args.slice(1);
|
|
24
|
+
} else {
|
|
25
|
+
requestPath = props.requestPath;
|
|
26
|
+
fnName = props.fnName;
|
|
27
|
+
isOptionsRequest = props.isOptionsRequest;
|
|
28
|
+
// args will convert to array on default
|
|
29
|
+
params = [].concat(props.args);
|
|
30
|
+
transfer = args[0] ? args[0] : [];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const header: RequestEntryHeader = [
|
|
34
|
+
RequestType.PromiseRequest,
|
|
35
|
+
seqId,
|
|
36
|
+
requestPath,
|
|
37
|
+
fnName,
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
const body = params;
|
|
41
|
+
return {
|
|
42
|
+
seqId,
|
|
43
|
+
transfer,
|
|
44
|
+
isOptionsRequest,
|
|
45
|
+
data: [header, body],
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
fn.lifecycle = SendMiddlewareLifecycle.Prepare;
|
|
50
|
+
return fn;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const prepareHostPortData = (channel: AbstractChannelProtocol) => {
|
|
54
|
+
const fn = (props: string | SendingProps, ...args: any[]) => {
|
|
55
|
+
let requestPath = '';
|
|
56
|
+
let fnName = '';
|
|
57
|
+
let params = [] as any[];
|
|
58
|
+
let transfer = [];
|
|
59
|
+
const seqId = channel.seqId;
|
|
60
|
+
let isOptionsRequest = false;
|
|
61
|
+
|
|
62
|
+
if (typeof props === 'string') {
|
|
63
|
+
requestPath = props;
|
|
64
|
+
fnName = args[0];
|
|
65
|
+
params = args.slice(1);
|
|
66
|
+
} else {
|
|
67
|
+
requestPath = props.requestPath;
|
|
68
|
+
fnName = props.fnName;
|
|
69
|
+
isOptionsRequest = props.isOptionsRequest;
|
|
70
|
+
// args will convert to array on default
|
|
71
|
+
params = [].concat(props.args);
|
|
72
|
+
transfer = args[0] ? args[0] : [];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const header: HostRequestEntryHeader = [
|
|
76
|
+
RequestType.PromiseRequest,
|
|
77
|
+
seqId,
|
|
78
|
+
requestPath,
|
|
79
|
+
fnName,
|
|
80
|
+
// @ts-ignore
|
|
81
|
+
channel.channelName,
|
|
82
|
+
];
|
|
83
|
+
|
|
84
|
+
const body = params;
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
seqId,
|
|
88
|
+
transfer,
|
|
89
|
+
isOptionsRequest,
|
|
90
|
+
data: [header, body],
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
fn.lifecycle = SendMiddlewareLifecycle.Prepare;
|
|
95
|
+
return fn;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export const prepareNormalData = (channel: AbstractChannelProtocol) => {
|
|
99
|
+
const fn = (props: string | SendingProps, ...args: any[]) => {
|
|
100
|
+
let requestPath = '';
|
|
101
|
+
let fnName = '';
|
|
102
|
+
let params = [] as any[];
|
|
103
|
+
const seqId = channel.seqId;
|
|
104
|
+
let isOptionsRequest = false;
|
|
105
|
+
|
|
106
|
+
if (typeof props === 'string') {
|
|
107
|
+
requestPath = props;
|
|
108
|
+
fnName = args[0];
|
|
109
|
+
params = args.slice(1);
|
|
110
|
+
} else {
|
|
111
|
+
requestPath = props.requestPath;
|
|
112
|
+
fnName = props.fnName;
|
|
113
|
+
isOptionsRequest = props.isOptionsRequest;
|
|
114
|
+
// args will convert to array on default
|
|
115
|
+
params = [].concat(props.args);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const header: RequestEntryHeader = [
|
|
119
|
+
RequestType.PromiseRequest,
|
|
120
|
+
seqId,
|
|
121
|
+
requestPath,
|
|
122
|
+
fnName,
|
|
123
|
+
];
|
|
124
|
+
|
|
125
|
+
const body = params;
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
seqId,
|
|
129
|
+
isOptionsRequest,
|
|
130
|
+
data: [header, body],
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
fn.lifecycle = SendMiddlewareLifecycle.Prepare;
|
|
135
|
+
|
|
136
|
+
return fn;
|
|
137
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { SenderMiddlewareOutput, SendMiddlewareLifecycle } from '../../types';
|
|
2
|
+
import AbstractChannelProtocol from '../AbstractChannelProtocol';
|
|
3
|
+
|
|
4
|
+
export const sendRequest = (channelProtocol: AbstractChannelProtocol) => {
|
|
5
|
+
const fn = (value: SenderMiddlewareOutput) => {
|
|
6
|
+
const { data, transfer } = value;
|
|
7
|
+
if (transfer) channelProtocol.channel.send(data, transfer);
|
|
8
|
+
else channelProtocol.channel.send(data);
|
|
9
|
+
|
|
10
|
+
return value;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
fn.lifecycle = SendMiddlewareLifecycle.Send;
|
|
14
|
+
return fn;
|
|
15
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { createDeferred } from '@x-oasis/deferred';
|
|
2
|
+
import { isEventMethod } from '../../common';
|
|
3
|
+
import { SenderMiddlewareOutput, SendMiddlewareLifecycle } from '../../types';
|
|
4
|
+
import AbstractChannelProtocol from '../AbstractChannelProtocol';
|
|
5
|
+
|
|
6
|
+
export const updateSeqInfo = (channelProtocol: AbstractChannelProtocol) => {
|
|
7
|
+
const fn = (value: SenderMiddlewareOutput) => {
|
|
8
|
+
const { data, seqId } = value;
|
|
9
|
+
const header = data[0];
|
|
10
|
+
const body = data[1];
|
|
11
|
+
const fnName = header[3];
|
|
12
|
+
|
|
13
|
+
// 如果说是event method的话,需要将body重制一下
|
|
14
|
+
if (fnName && isEventMethod(fnName)) {
|
|
15
|
+
channelProtocol.requestEvents.set(`${seqId}`, body[0]);
|
|
16
|
+
data[1] = [];
|
|
17
|
+
} else {
|
|
18
|
+
const returnValue = createDeferred();
|
|
19
|
+
channelProtocol.ongoingRequests.set(`${seqId}`, returnValue);
|
|
20
|
+
value.returnValue = returnValue;
|
|
21
|
+
}
|
|
22
|
+
return value;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
fn.lifecycle = SendMiddlewareLifecycle.Transfrom;
|
|
26
|
+
return fn;
|
|
27
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MiddlewareContext,
|
|
3
|
+
PendingSendEntry,
|
|
4
|
+
MiddlewareFunction,
|
|
5
|
+
SendMiddlewareLifecycle,
|
|
6
|
+
} from '../../types';
|
|
7
|
+
|
|
8
|
+
export const resumeMiddlewares = (
|
|
9
|
+
middlewares: any,
|
|
10
|
+
entry: PendingSendEntry
|
|
11
|
+
) => {
|
|
12
|
+
let start = false;
|
|
13
|
+
|
|
14
|
+
return middlewares.reduce((a: any, b: MiddlewareFunction) => {
|
|
15
|
+
if (!b.lifecycle) return a;
|
|
16
|
+
if (a.lifecycle >= b.lifecycle && b.displayName === a.fnName) {
|
|
17
|
+
start = true;
|
|
18
|
+
}
|
|
19
|
+
if (!start) return a;
|
|
20
|
+
|
|
21
|
+
const targetLifecycle = a?.middlewareContext?.minLifecycle;
|
|
22
|
+
const currentLifecycle = b?.lifecycle;
|
|
23
|
+
|
|
24
|
+
// @ts-ignore
|
|
25
|
+
if (
|
|
26
|
+
targetLifecycle &&
|
|
27
|
+
currentLifecycle &&
|
|
28
|
+
currentLifecycle < targetLifecycle
|
|
29
|
+
) {
|
|
30
|
+
return a;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return b(a);
|
|
34
|
+
}, entry);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const runMiddlewares = (
|
|
38
|
+
middlewares: any,
|
|
39
|
+
args: any[],
|
|
40
|
+
_context?: MiddlewareContext
|
|
41
|
+
) => {
|
|
42
|
+
const context = {
|
|
43
|
+
isResumed: false,
|
|
44
|
+
startLifecycle: SendMiddlewareLifecycle.Initial,
|
|
45
|
+
minLifecycle: SendMiddlewareLifecycle.Initial,
|
|
46
|
+
...(_context || {}),
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
return middlewares.reduce((a: any, b: MiddlewareFunction, index: number) => {
|
|
50
|
+
if (!index) return b(...a);
|
|
51
|
+
if (index === 1) {
|
|
52
|
+
a.middlewareContext = context;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const targetLifecycle = a?.middlewareContext?.minLifecycle;
|
|
56
|
+
const currentLifecycle = b?.lifecycle;
|
|
57
|
+
|
|
58
|
+
if (
|
|
59
|
+
targetLifecycle &&
|
|
60
|
+
currentLifecycle &&
|
|
61
|
+
currentLifecycle < targetLifecycle
|
|
62
|
+
) {
|
|
63
|
+
return a;
|
|
64
|
+
}
|
|
65
|
+
return b(a);
|
|
66
|
+
}, args);
|
|
67
|
+
};
|
package/src/common.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { isUpperAsciiLetter } from '@x-oasis/is-ascii';
|
|
2
|
+
|
|
3
|
+
export const isEventMethod = (name: string) => {
|
|
4
|
+
if (typeof name !== 'string') return false;
|
|
5
|
+
return (
|
|
6
|
+
name[0] === 'o' && name[1] === 'n' && isUpperAsciiLetter(name.charCodeAt(2))
|
|
7
|
+
);
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const isAssignPassingPortMethod = (name: string) => {
|
|
11
|
+
return /^assignPassingPort$/.test(name);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const isAcquirePortMethod = (name: string) => {
|
|
15
|
+
return /^acquire.*Port$/.test(name);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const isOptionsMethod = (name: string) => {
|
|
19
|
+
return /Options$/.test(name) || /OptionsRequest$/.test(name);
|
|
20
|
+
};
|
package/src/error.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/* eslint-disable no-param-reassign */
|
|
2
|
+
|
|
3
|
+
export interface ErrorResponseDetail<Error = unknown> {
|
|
4
|
+
readonly code: number;
|
|
5
|
+
readonly message: string;
|
|
6
|
+
readonly data?: Error;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type ID = string | number | null | undefined;
|
|
10
|
+
|
|
11
|
+
export interface ErrorResponse<Error = unknown> {
|
|
12
|
+
readonly jsonrpc: '2.0';
|
|
13
|
+
readonly id?: ID;
|
|
14
|
+
readonly error: ErrorResponseDetail<Error>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const makeErrorResponse = <T>(
|
|
18
|
+
id: ID,
|
|
19
|
+
code: number,
|
|
20
|
+
message: string,
|
|
21
|
+
data?: T
|
|
22
|
+
): ErrorResponse<T> => {
|
|
23
|
+
if (id === undefined) id = null;
|
|
24
|
+
code = Math.floor(code);
|
|
25
|
+
if (Number.isNaN(code)) code = -1;
|
|
26
|
+
const x: ErrorResponse<T> = {
|
|
27
|
+
jsonrpc: '2.0',
|
|
28
|
+
id,
|
|
29
|
+
error: { code, message, data },
|
|
30
|
+
};
|
|
31
|
+
return x;
|
|
32
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { default as RPCServiceHost } from './rpc-service/RPCServiceHost';
|
|
2
|
+
export { default as rpcServiceProvider } from './rpc-service/RPCServiceProvider';
|
|
3
|
+
export { default as ProxyRPCClient } from './rpc-service/ProxyRPCClient';
|
|
4
|
+
export * from './types';
|
|
5
|
+
export { isEventMethod } from './common';
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isEventMethod,
|
|
3
|
+
isAssignPassingPortMethod,
|
|
4
|
+
isOptionsMethod,
|
|
5
|
+
} from '../common';
|
|
6
|
+
import { ProxyRPCClientProps, ProxyRPCClientChannel } from '../types';
|
|
7
|
+
|
|
8
|
+
class ProxyRPCClient {
|
|
9
|
+
private requestPath: string;
|
|
10
|
+
|
|
11
|
+
private _channelProtocol: ProxyRPCClientChannel;
|
|
12
|
+
|
|
13
|
+
constructor(props: ProxyRPCClientProps) {
|
|
14
|
+
this._channelProtocol = props.channel;
|
|
15
|
+
this.requestPath = props.requestPath;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
get channelProtocol() {
|
|
19
|
+
if (typeof this._channelProtocol === 'function')
|
|
20
|
+
return this._channelProtocol();
|
|
21
|
+
return this._channelProtocol;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
createProxy<T = object>(): T {
|
|
25
|
+
return new Proxy(
|
|
26
|
+
{},
|
|
27
|
+
{
|
|
28
|
+
get: (target, key) => {
|
|
29
|
+
return (...args: any[]) => {
|
|
30
|
+
const fnName = key.toString();
|
|
31
|
+
if (!this.channelProtocol) {
|
|
32
|
+
throw new Error(
|
|
33
|
+
`[ProxyRPCClient error] \`this.channelProtocol\` is null, when invoke function ${fnName}`
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (isAssignPassingPortMethod(fnName)) {
|
|
38
|
+
const ports = args.pop();
|
|
39
|
+
this.channelProtocol.send(
|
|
40
|
+
{
|
|
41
|
+
requestPath: this.requestPath,
|
|
42
|
+
fnName,
|
|
43
|
+
args,
|
|
44
|
+
},
|
|
45
|
+
[].concat(ports)
|
|
46
|
+
);
|
|
47
|
+
} else if (isEventMethod(fnName)) {
|
|
48
|
+
this.channelProtocol.send({
|
|
49
|
+
requestPath: this.requestPath,
|
|
50
|
+
fnName,
|
|
51
|
+
args,
|
|
52
|
+
});
|
|
53
|
+
} else if (
|
|
54
|
+
/**
|
|
55
|
+
* 主要是为了解决刚开始channel connected状态是待确定,而所有的rpc 原则上都是先
|
|
56
|
+
* 过isConnected的判断;但是想要确保是否通的,这个时候其实还是要发rpc确认的,
|
|
57
|
+
* 那么这个时候这个就不能够受 isConnected约束;否则你就一直没有请求能够发出去了。
|
|
58
|
+
*/
|
|
59
|
+
isOptionsMethod(fnName)
|
|
60
|
+
) {
|
|
61
|
+
this.channelProtocol.send({
|
|
62
|
+
isOptionsRequest: true,
|
|
63
|
+
requestPath: this.requestPath,
|
|
64
|
+
fnName,
|
|
65
|
+
args,
|
|
66
|
+
});
|
|
67
|
+
} else {
|
|
68
|
+
this.channelProtocol.send({
|
|
69
|
+
requestPath: this.requestPath,
|
|
70
|
+
fnName,
|
|
71
|
+
args,
|
|
72
|
+
// @ts-ignore
|
|
73
|
+
}).promise;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
},
|
|
77
|
+
}
|
|
78
|
+
) as any as T;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export default ProxyRPCClient;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { IService, ServiceHandlerPath } from '../types';
|
|
2
|
+
|
|
3
|
+
class RPCServiceHost {
|
|
4
|
+
protected readonly hostPath: string;
|
|
5
|
+
|
|
6
|
+
handlersMap = new Map<ServiceHandlerPath, IService>();
|
|
7
|
+
|
|
8
|
+
constructor(hostPath: string) {
|
|
9
|
+
this.hostPath = hostPath;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
registerServiceHandler(handlerPath: ServiceHandlerPath, service: IService) {
|
|
13
|
+
this.handlersMap.set(handlerPath, service);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
getHandlers(handlerPath: ServiceHandlerPath) {
|
|
17
|
+
const handlers = this.handlersMap.get(handlerPath);
|
|
18
|
+
return handlers;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
getHandler(handlerPath: ServiceHandlerPath, fnName: string) {
|
|
22
|
+
const handlers = this.handlersMap.get(handlerPath);
|
|
23
|
+
// should bind to current service object
|
|
24
|
+
if (handlers && handlers[fnName]) return handlers[fnName].bind(handlers);
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
merge(serviceHost: RPCServiceHost) {
|
|
29
|
+
for (const [key, value] of serviceHost.handlersMap) {
|
|
30
|
+
this.registerServiceHandler(key, value);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default RPCServiceHost;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import RPCServiceHandler from './RPCServiceHost';
|
|
2
|
+
|
|
3
|
+
class RPCServiceProvider {
|
|
4
|
+
private hostMap = new Map<string, RPCServiceHandler>();
|
|
5
|
+
|
|
6
|
+
getHost(hostPath: string) {
|
|
7
|
+
return this.hostMap.get(hostPath);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
registerHost(hostPath: string) {
|
|
11
|
+
const host = this.hostMap.get(hostPath);
|
|
12
|
+
if (host) return host;
|
|
13
|
+
this.hostMap.set(hostPath, new RPCServiceHandler(hostPath));
|
|
14
|
+
return this.hostMap.get(hostPath);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
resetHost(hostPath: string) {
|
|
18
|
+
this.hostMap.set(hostPath, new RPCServiceHandler(hostPath));
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default new RPCServiceProvider();
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type IMessageChannelOnClose = () => void;
|
|
2
|
+
export type IMessageChannelOnError = () => void;
|
|
3
|
+
export type IMessageChannelOnMessage = (message: any) => void;
|
|
4
|
+
export type IMessageChannelSend = (
|
|
5
|
+
requestPath: string,
|
|
6
|
+
fnName: string,
|
|
7
|
+
...args: any[]
|
|
8
|
+
) => void;
|
|
9
|
+
export type IMessageChannelDisconnect = () => void;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* A channel is a bidirectional communications channel
|
|
13
|
+
*/
|
|
14
|
+
export type IMessageChannel = {
|
|
15
|
+
onClose?: IMessageChannelOnClose;
|
|
16
|
+
|
|
17
|
+
onError?: IMessageChannelOnError;
|
|
18
|
+
|
|
19
|
+
onMessage: IMessageChannelOnMessage;
|
|
20
|
+
|
|
21
|
+
send: IMessageChannelSend;
|
|
22
|
+
|
|
23
|
+
disconnect: IMessageChannelDisconnect;
|
|
24
|
+
};
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { IpcRenderer, UtilityProcess, WebContents } from 'electron';
|
|
2
|
+
import MessageChannelProtocol from '../channel-protocol/MessageChannelProtocol';
|
|
3
|
+
import RPCServiceHost from '../rpc-service/RPCServiceHost';
|
|
4
|
+
|
|
5
|
+
export interface ChannelPort {
|
|
6
|
+
on(event: 'message', listener: (messageEvent: MessageEvent) => void): this;
|
|
7
|
+
removeListener(
|
|
8
|
+
event: 'message',
|
|
9
|
+
listener: (messageEvent: MessageEvent) => void
|
|
10
|
+
): this;
|
|
11
|
+
postMessage(message: any, transfer?: MainPort[]): void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type UtilityMessageChannelPortStoreProps = {
|
|
15
|
+
name: string;
|
|
16
|
+
port: ParentPort;
|
|
17
|
+
masterProcessName: string;
|
|
18
|
+
clientMiddlewares?: ClientMiddleware[];
|
|
19
|
+
senderMiddlewares?: SenderMiddleware[];
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type OnMessageEntry = {
|
|
23
|
+
data: any;
|
|
24
|
+
ports: any;
|
|
25
|
+
};
|
|
26
|
+
export type SenderEntry = any;
|
|
27
|
+
|
|
28
|
+
export type ClientMiddleware = (
|
|
29
|
+
channel?: MessageChannelProtocol
|
|
30
|
+
) => (v: OnMessageEntry) => OnMessageEntry;
|
|
31
|
+
|
|
32
|
+
export type SenderMiddleware = (
|
|
33
|
+
channel?: MessageChannelProtocol
|
|
34
|
+
) => (data: SenderEntry) => SenderEntry;
|
|
35
|
+
|
|
36
|
+
export type AbstractChannelProtocolProps = {
|
|
37
|
+
serviceHost?: RPCServiceHost;
|
|
38
|
+
connected?: boolean;
|
|
39
|
+
description?: string;
|
|
40
|
+
masterProcessName?: string;
|
|
41
|
+
clientMiddlewares?: ClientMiddleware[];
|
|
42
|
+
senderMiddlewares?: SenderMiddleware[];
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type DeferredMessageChannelProtocolProps =
|
|
46
|
+
AbstractChannelProtocolProps & {
|
|
47
|
+
port?: MainPort;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export type MessageChannelProtocolProps = AbstractChannelProtocolProps & {
|
|
51
|
+
port?: MainPort;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export type ProcessChannelProtocolProps = {
|
|
55
|
+
process: UtilityProcess;
|
|
56
|
+
} & AbstractChannelProtocolProps;
|
|
57
|
+
|
|
58
|
+
export type IPCMainGlobalChannelProtocolProps = AbstractChannelProtocolProps & {
|
|
59
|
+
channelName: string;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export type IPCMainChannelProtocolProps = {
|
|
63
|
+
channelName: string;
|
|
64
|
+
webContents: WebContents;
|
|
65
|
+
} & AbstractChannelProtocolProps;
|
|
66
|
+
|
|
67
|
+
export type IPCRendererChannelProtocolProps = {
|
|
68
|
+
channelName: string;
|
|
69
|
+
ipcRenderer: IpcRenderer;
|
|
70
|
+
projectName: string;
|
|
71
|
+
} & AbstractChannelProtocolProps;
|
|
72
|
+
|
|
73
|
+
export interface ParentPort extends NodeJS.EventEmitter {
|
|
74
|
+
on(event: 'message', listener: (messageEvent: MessageEvent) => void): this;
|
|
75
|
+
once(event: 'message', listener: (messageEvent: MessageEvent) => void): this;
|
|
76
|
+
addListener(
|
|
77
|
+
event: 'message',
|
|
78
|
+
listener: (messageEvent: MessageEvent) => void
|
|
79
|
+
): this;
|
|
80
|
+
removeListener(
|
|
81
|
+
event: 'message',
|
|
82
|
+
listener: (messageEvent: MessageEvent) => void
|
|
83
|
+
): this;
|
|
84
|
+
postMessage(message: any): void;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export type UtilityNodeJSProcess = NodeJS.Process;
|
|
88
|
+
|
|
89
|
+
export interface MainPort extends NodeJS.EventEmitter {
|
|
90
|
+
// Docs: https://electronjs.org/docs/api/message-port-main
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Emitted when the remote end of a MessagePortMain object becomes disconnected.
|
|
94
|
+
*/
|
|
95
|
+
/**
|
|
96
|
+
* Emitted when a MessagePortMain object receives a message.
|
|
97
|
+
*/
|
|
98
|
+
on(event: 'close', listener: Function): this;
|
|
99
|
+
on(event: 'message', listener: (messageEvent: MessageEvent) => void): this;
|
|
100
|
+
off(event: 'close', listener: Function): this;
|
|
101
|
+
off(event: 'message', listener: (messageEvent: MessageEvent) => void): this;
|
|
102
|
+
once(event: 'close', listener: Function): this;
|
|
103
|
+
once(event: 'message', listener: (messageEvent: MessageEvent) => void): this;
|
|
104
|
+
addListener(event: 'close', listener: Function): this;
|
|
105
|
+
addListener(
|
|
106
|
+
event: 'message',
|
|
107
|
+
listener: (messageEvent: MessageEvent) => void
|
|
108
|
+
): this;
|
|
109
|
+
removeListener(event: 'close', listener: Function): this;
|
|
110
|
+
removeListener(
|
|
111
|
+
event: 'message',
|
|
112
|
+
listener: (messageEvent: MessageEvent) => void
|
|
113
|
+
): this;
|
|
114
|
+
/**
|
|
115
|
+
* Disconnects the port, so it is no longer active.
|
|
116
|
+
*/
|
|
117
|
+
close(): void;
|
|
118
|
+
/**
|
|
119
|
+
* Sends a message from the port, and optionally, transfers ownership of objects to
|
|
120
|
+
* other browsing contexts.
|
|
121
|
+
*/
|
|
122
|
+
postMessage(message: any, transfer?: MainPort[]): void;
|
|
123
|
+
/**
|
|
124
|
+
* Starts the sending of messages queued on the port. Messages will be queued until
|
|
125
|
+
* this method is called.
|
|
126
|
+
*/
|
|
127
|
+
start(): void;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function isUtilityProcess(
|
|
131
|
+
process: NodeJS.Process
|
|
132
|
+
): process is UtilityNodeJSProcess {
|
|
133
|
+
return !!(process as UtilityNodeJSProcess).parentPort;
|
|
134
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Deferred } from '@x-oasis/deferred';
|
|
2
|
+
|
|
3
|
+
import { HostRequestEntry, RequestEntry } from './rpc';
|
|
4
|
+
|
|
5
|
+
export type MiddlewareFunction = {
|
|
6
|
+
(...args: any[]): any;
|
|
7
|
+
displayName?: string;
|
|
8
|
+
lifecycle?: SendMiddlewareLifecycle;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type MessageOutput = {
|
|
12
|
+
event: any;
|
|
13
|
+
ports: any;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type NormalizedRawMessageOutput = MessageOutput & {
|
|
17
|
+
data: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type DeserializedMessageOutput = MessageOutput & {
|
|
21
|
+
data: HostRequestEntry | RequestEntry;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type SenderMiddlewareOutput = {
|
|
25
|
+
data: any;
|
|
26
|
+
transfer: any;
|
|
27
|
+
seqId: number;
|
|
28
|
+
returnValue: Deferred;
|
|
29
|
+
isOptionsRequest: boolean;
|
|
30
|
+
middlewareContext: MiddlewareContext;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type PendingSendEntry = SenderMiddlewareOutput & {
|
|
34
|
+
fnName: string;
|
|
35
|
+
lifecycle: SendMiddlewareLifecycle;
|
|
36
|
+
middlewareContext: MiddlewareContext;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export type MiddlewareContext = {
|
|
40
|
+
isResumed?: boolean;
|
|
41
|
+
startLifecycle: SendMiddlewareLifecycle;
|
|
42
|
+
minLifecycle: SendMiddlewareLifecycle;
|
|
43
|
+
reserved: PendingSendEntry;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export enum SendMiddlewareLifecycle {
|
|
47
|
+
Initial = 0,
|
|
48
|
+
Prepare = 10,
|
|
49
|
+
Transfrom = 20,
|
|
50
|
+
DataOperation = 30,
|
|
51
|
+
Send = 40,
|
|
52
|
+
Aborted = 100,
|
|
53
|
+
}
|