@x-oasis/async-call-rpc 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 +48 -0
- package/dist/async-call-rpc.cjs.development.js +1275 -0
- package/dist/async-call-rpc.cjs.development.js.map +1 -0
- package/dist/async-call-rpc.cjs.production.min.js +2 -0
- package/dist/async-call-rpc.cjs.production.min.js.map +1 -0
- package/dist/async-call-rpc.esm.js +1559 -0
- package/dist/async-call-rpc.esm.js.map +1 -0
- package/dist/buffer/BufferFactory.d.ts +12 -0
- package/dist/buffer/DataBuffer.d.ts +2 -0
- package/dist/buffer/MessagePackBuffer.d.ts +10 -0
- package/dist/buffer/ReadBaseBuffer.d.ts +5 -0
- package/dist/buffer/ReadBuffer.d.ts +14 -0
- package/dist/buffer/SerializationFormat.d.ts +16 -0
- package/dist/buffer/WriteBaseBuffer.d.ts +5 -0
- package/dist/buffer/WriteBuffer.d.ts +5 -0
- package/dist/buffer/examples.d.ts +10 -0
- package/dist/buffer/index.d.ts +8 -0
- package/dist/common.d.ts +4 -0
- package/dist/endpoint/ProxyRPCClient.d.ts +12 -0
- package/dist/endpoint/RPCClientHost.d.ts +12 -0
- package/dist/endpoint/RPCService.d.ts +20 -0
- package/dist/endpoint/RPCServiceHost.d.ts +10 -0
- package/dist/error.d.ts +21 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +8 -0
- package/dist/middlewares/buffer.d.ts +18 -0
- package/dist/middlewares/handleDisconnectedRequest.d.ts +7 -0
- package/dist/middlewares/handlePortRequest.d.ts +3 -0
- package/dist/middlewares/handleRequest.d.ts +3 -0
- package/dist/middlewares/handleRequestUtils.d.ts +10 -0
- package/dist/middlewares/handleResponse.d.ts +3 -0
- package/dist/middlewares/index.d.ts +7 -0
- package/dist/middlewares/logger.d.ts +4 -0
- package/dist/middlewares/normalize.d.ts +14 -0
- package/dist/middlewares/prepareRequestData.d.ts +28 -0
- package/dist/middlewares/sendRequest.d.ts +6 -0
- package/dist/middlewares/updateSeqInfo.d.ts +6 -0
- package/dist/middlewares/utils.d.ts +3 -0
- package/dist/protocol/AbstractChannelProtocol.d.ts +55 -0
- package/dist/protocol/MessageChannel.d.ts +18 -0
- package/dist/protocol/WebSocketChannel.d.ts +23 -0
- package/dist/protocol/WorkerChannel.d.ts +11 -0
- package/dist/types/buffer.d.ts +4 -0
- package/dist/types/channel.d.ts +27 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/middleware.d.ts +44 -0
- package/dist/types/proxyChannel.d.ts +3 -0
- package/dist/types/proxyService.d.ts +11 -0
- package/dist/types/rpc.d.ts +25 -0
- package/dist/types/rpcProtocol.d.ts +22 -0
- package/dist/utils/constants.d.ts +5 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/jsonrpc.d.ts +36 -0
- package/package.json +36 -0
- package/src/buffer/ARCHITECTURE.md +298 -0
- package/src/buffer/BufferFactory.ts +124 -0
- package/src/buffer/CHANGELOG.md +207 -0
- package/src/buffer/DataBuffer.ts +1 -0
- package/src/buffer/MessagePackBuffer.ts +79 -0
- package/src/buffer/OPTIMIZATION.md +258 -0
- package/src/buffer/README.md +147 -0
- package/src/buffer/ReadBaseBuffer.ts +20 -0
- package/src/buffer/ReadBuffer.ts +58 -0
- package/src/buffer/SerializationFormat.ts +81 -0
- package/src/buffer/WriteBaseBuffer.ts +20 -0
- package/src/buffer/WriteBuffer.ts +15 -0
- package/src/buffer/examples.ts +242 -0
- package/src/buffer/index.ts +15 -0
- package/src/common.ts +20 -0
- package/src/endpoint/ProxyRPCClient.ts +64 -0
- package/src/endpoint/RPCClientHost.ts +45 -0
- package/src/endpoint/RPCService.ts +54 -0
- package/src/endpoint/RPCServiceHost.ts +18 -0
- package/src/error.ts +98 -0
- package/src/index.ts +16 -0
- package/src/middlewares/buffer.ts +33 -0
- package/src/middlewares/handleDisconnectedRequest.ts +30 -0
- package/src/middlewares/handlePortRequest.ts +141 -0
- package/src/middlewares/handleRequest.ts +128 -0
- package/src/middlewares/handleRequestUtils.ts +43 -0
- package/src/middlewares/handleResponse.ts +36 -0
- package/src/middlewares/index.ts +11 -0
- package/src/middlewares/logger.ts +22 -0
- package/src/middlewares/normalize.ts +167 -0
- package/src/middlewares/prepareRequestData.ts +137 -0
- package/src/middlewares/sendRequest.ts +15 -0
- package/src/middlewares/updateSeqInfo.ts +34 -0
- package/src/middlewares/utils.ts +67 -0
- package/src/protocol/AbstractChannelProtocol.ts +343 -0
- package/src/protocol/MessageChannel.ts +80 -0
- package/src/protocol/WebSocketChannel.ts +179 -0
- package/src/protocol/WorkerChannel.ts +36 -0
- package/src/types/buffer.ts +5 -0
- package/src/types/channel.ts +50 -0
- package/src/types/index.ts +9 -0
- package/src/types/messageChannel.ts +133 -0
- package/src/types/middleware.ts +54 -0
- package/src/types/proxyChannel.ts +3 -0
- package/src/types/proxyService.ts +18 -0
- package/src/types/rpc.ts +61 -0
- package/src/types/rpcProtocol.ts +24 -0
- package/src/utils/constants.ts +17 -0
- package/src/utils/index.ts +5 -0
- package/src/utils/jsonrpc.ts +242 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import ProxyRPCClient from './ProxyRPCClient';
|
|
2
|
+
import AbstractChannelProtocol from '../protocol/AbstractChannelProtocol';
|
|
3
|
+
|
|
4
|
+
class RPCClientHost {
|
|
5
|
+
protected readonly hostPath: string;
|
|
6
|
+
|
|
7
|
+
private hostMap = new Map<string, ProxyRPCClient>();
|
|
8
|
+
|
|
9
|
+
// handlersMap = new Map<ServiceHandlerPath, IService>();
|
|
10
|
+
|
|
11
|
+
registerClient(
|
|
12
|
+
requestPath: string,
|
|
13
|
+
options?: {
|
|
14
|
+
channel?: AbstractChannelProtocol;
|
|
15
|
+
}
|
|
16
|
+
) {
|
|
17
|
+
const client = new ProxyRPCClient(requestPath, options);
|
|
18
|
+
this.hostMap.set(requestPath, client);
|
|
19
|
+
return client;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// registerServiceHandler(handlerPath: ServiceHandlerPath, service: IService) {
|
|
23
|
+
// this.handlersMap.set(handlerPath, service);
|
|
24
|
+
// }
|
|
25
|
+
|
|
26
|
+
// getHandlers(handlerPath: ServiceHandlerPath) {
|
|
27
|
+
// const handlers = this.handlersMap.get(handlerPath);
|
|
28
|
+
// return handlers;
|
|
29
|
+
// }
|
|
30
|
+
|
|
31
|
+
// getHandler(handlerPath: ServiceHandlerPath, fnName: string) {
|
|
32
|
+
// const handlers = this.handlersMap.get(handlerPath);
|
|
33
|
+
// // should bind to current service object
|
|
34
|
+
// if (handlers && handlers[fnName]) return handlers[fnName].bind(handlers);
|
|
35
|
+
// return null;
|
|
36
|
+
// }
|
|
37
|
+
|
|
38
|
+
// merge(serviceHost: RPCClientHost) {
|
|
39
|
+
// for (const [key, value] of serviceHost.handlersMap) {
|
|
40
|
+
// this.registerServiceHandler(key, value);
|
|
41
|
+
// }
|
|
42
|
+
// }
|
|
43
|
+
}
|
|
44
|
+
export { RPCClientHost };
|
|
45
|
+
export default new RPCClientHost();
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import AbstractChannelProtocol from '../protocol/AbstractChannelProtocol';
|
|
2
|
+
import { RPCServiceHost } from './RPCServiceHost';
|
|
3
|
+
import { ServiceHandlers } from '../types/proxyService';
|
|
4
|
+
|
|
5
|
+
class RPCService {
|
|
6
|
+
private channel: AbstractChannelProtocol;
|
|
7
|
+
readonly serviceHost: RPCServiceHost;
|
|
8
|
+
readonly servicePath: string;
|
|
9
|
+
readonly handlersMap = new Map<string, (...args: any[]) => any>();
|
|
10
|
+
|
|
11
|
+
constructor(
|
|
12
|
+
servicePath: string,
|
|
13
|
+
options?: {
|
|
14
|
+
channel?: AbstractChannelProtocol;
|
|
15
|
+
handlers: ServiceHandlers;
|
|
16
|
+
serviceHost?: RPCServiceHost;
|
|
17
|
+
}
|
|
18
|
+
) {
|
|
19
|
+
const { channel, handlers, serviceHost } = options || {};
|
|
20
|
+
this.servicePath = servicePath;
|
|
21
|
+
this.serviceHost = serviceHost;
|
|
22
|
+
if (channel) {
|
|
23
|
+
this.setChannel(channel);
|
|
24
|
+
}
|
|
25
|
+
this.registerHandlers(handlers);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
setChannel(channel: AbstractChannelProtocol) {
|
|
29
|
+
this.channel = channel;
|
|
30
|
+
this.channel.setService(this);
|
|
31
|
+
this.channel.on(this.handleMessage.bind(this));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
registerHandlers(handlers: Record<string, (...args: any[]) => any>) {
|
|
35
|
+
if (!handlers) return;
|
|
36
|
+
for (const [methodName, handler] of Object.entries(handlers)) {
|
|
37
|
+
this.registerHandler(methodName, handler);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
handleMessage(...args: any[]) {
|
|
42
|
+
this.channel.onMessage(...args);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
registerHandler(methodName: string, handler: (...args: any[]) => any) {
|
|
46
|
+
this.handlersMap.set(methodName, handler);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
getHandler(methodName: string) {
|
|
50
|
+
return this.handlersMap.get(methodName);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export default RPCService;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ServiceHandlers } from '../types/proxyService';
|
|
2
|
+
import RPCService from './RPCService';
|
|
3
|
+
|
|
4
|
+
class RPCServiceHost {
|
|
5
|
+
protected readonly hostPath: string;
|
|
6
|
+
|
|
7
|
+
private hostMap = new Map<string, RPCService>();
|
|
8
|
+
|
|
9
|
+
// handlersMap = new Map<ServiceHandlerPath, IService>();
|
|
10
|
+
|
|
11
|
+
registerService(servicePath: string, serviceHandlers: ServiceHandlers) {
|
|
12
|
+
const service = new RPCService(servicePath, { handlers: serviceHandlers });
|
|
13
|
+
this.hostMap.set(servicePath, service);
|
|
14
|
+
return service;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export { RPCServiceHost };
|
|
18
|
+
export default new RPCServiceHost();
|
package/src/error.ts
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/* eslint-disable no-param-reassign */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* JSONRPC Error Response Detail
|
|
5
|
+
* Based on JSONRPC 2.0 specification
|
|
6
|
+
*/
|
|
7
|
+
export interface ErrorResponseDetail<Error = unknown> {
|
|
8
|
+
readonly code: number;
|
|
9
|
+
readonly message: string;
|
|
10
|
+
readonly data?: Error;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* JSONRPC Request/Response ID type
|
|
15
|
+
* Can be string, number, null, or undefined (for notifications)
|
|
16
|
+
*/
|
|
17
|
+
export type ID = string | number | null | undefined;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* JSONRPC Error Response
|
|
21
|
+
* Based on JSONRPC 2.0 specification
|
|
22
|
+
*/
|
|
23
|
+
export interface ErrorResponse<Error = unknown> {
|
|
24
|
+
readonly jsonrpc: '2.0';
|
|
25
|
+
readonly id?: ID;
|
|
26
|
+
readonly error: ErrorResponseDetail<Error>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Standard JSONRPC 2.0 Error Codes
|
|
31
|
+
* Based on JSONRPC 2.0 specification section 5.1
|
|
32
|
+
*/
|
|
33
|
+
export enum JSONRPCErrorCode {
|
|
34
|
+
/**
|
|
35
|
+
* Parse error (-32700)
|
|
36
|
+
* Invalid JSON was received by the server.
|
|
37
|
+
* An error occurred on the server while parsing the JSON text.
|
|
38
|
+
*/
|
|
39
|
+
ParseError = -32700,
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Invalid Request (-32600)
|
|
43
|
+
* The JSON sent is not a valid Request object.
|
|
44
|
+
*/
|
|
45
|
+
InvalidRequest = -32600,
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Method not found (-32601)
|
|
49
|
+
* The method does not exist / is not available.
|
|
50
|
+
*/
|
|
51
|
+
MethodNotFound = -32601,
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Invalid params (-32602)
|
|
55
|
+
* Invalid method parameter(s).
|
|
56
|
+
*/
|
|
57
|
+
InvalidParams = -32602,
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Internal error (-32603)
|
|
61
|
+
* Internal JSON-RPC error.
|
|
62
|
+
*/
|
|
63
|
+
InternalError = -32603,
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Server error (-32000 to -32099)
|
|
67
|
+
* Reserved for implementation-defined server-errors.
|
|
68
|
+
* The remainder of the space is available for application defined errors.
|
|
69
|
+
*/
|
|
70
|
+
ServerErrorStart = -32000,
|
|
71
|
+
ServerErrorEnd = -32099,
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Create a JSONRPC error response object
|
|
76
|
+
* This function is kept for backward compatibility.
|
|
77
|
+
* For new code, prefer using functions from utils/jsonrpc.ts
|
|
78
|
+
*/
|
|
79
|
+
export const makeErrorResponse = <T>(
|
|
80
|
+
id: ID,
|
|
81
|
+
code: number,
|
|
82
|
+
message: string,
|
|
83
|
+
data?: T
|
|
84
|
+
): ErrorResponse<T> => {
|
|
85
|
+
if (id === undefined) id = null;
|
|
86
|
+
code = Math.floor(code);
|
|
87
|
+
if (Number.isNaN(code)) code = -1;
|
|
88
|
+
const x: ErrorResponse<T> = {
|
|
89
|
+
jsonrpc: '2.0',
|
|
90
|
+
id,
|
|
91
|
+
error: { code, message, data },
|
|
92
|
+
};
|
|
93
|
+
// Remove undefined data field
|
|
94
|
+
if (x.error.data === undefined) {
|
|
95
|
+
delete (x.error as any).data;
|
|
96
|
+
}
|
|
97
|
+
return x;
|
|
98
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import clientHost from './endpoint/RPCClientHost';
|
|
2
|
+
import ProxyRPCClient from './endpoint/ProxyRPCClient';
|
|
3
|
+
import RPCService from './endpoint/RPCService';
|
|
4
|
+
import serviceHost from './endpoint/RPCServiceHost';
|
|
5
|
+
|
|
6
|
+
export { default as MessageChannel } from './protocol/MessageChannel';
|
|
7
|
+
export { default as WorkerChannel } from './protocol/WorkerChannel';
|
|
8
|
+
export { default as WebSocketChannel } from './protocol/WebSocketChannel';
|
|
9
|
+
|
|
10
|
+
export { ProxyRPCClient, RPCService, clientHost, serviceHost };
|
|
11
|
+
|
|
12
|
+
// Export JSONRPC utilities and types
|
|
13
|
+
export * from './utils';
|
|
14
|
+
// Export error types but not makeErrorResponse to avoid conflict (it's in utils/jsonrpc.ts)
|
|
15
|
+
export type { ErrorResponse, ErrorResponseDetail, ID } from './error';
|
|
16
|
+
export { JSONRPCErrorCode } from './error';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {
|
|
2
|
+
NormalizedRawMessageOutput,
|
|
3
|
+
SenderMiddlewareOutput,
|
|
4
|
+
SendMiddlewareLifecycle,
|
|
5
|
+
} from '../types';
|
|
6
|
+
import AbstractChannelProtocol from '../protocol/AbstractChannelProtocol';
|
|
7
|
+
|
|
8
|
+
export const serialize = (channel: AbstractChannelProtocol) => {
|
|
9
|
+
const fn = (value: SenderMiddlewareOutput) => ({
|
|
10
|
+
...value,
|
|
11
|
+
data: channel.writeBuffer.encode(value.data),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
fn.lifecycle = SendMiddlewareLifecycle.DataOperation;
|
|
15
|
+
return fn;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const deserialize =
|
|
19
|
+
(channel: AbstractChannelProtocol) => (value: NormalizedRawMessageOutput) => {
|
|
20
|
+
const { data } = value;
|
|
21
|
+
let decoded = data;
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
decoded = channel.readBuffer.decode(data);
|
|
25
|
+
} catch (err) {
|
|
26
|
+
console.error('[decode error]', data, err);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
...value,
|
|
31
|
+
data: decoded,
|
|
32
|
+
};
|
|
33
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { SenderMiddlewareOutput, SendMiddlewareLifecycle } from '../types';
|
|
2
|
+
import AbstractChannelProtocol from '../protocol/AbstractChannelProtocol';
|
|
3
|
+
|
|
4
|
+
export const handleDisconnectedRequest = (
|
|
5
|
+
protocol: AbstractChannelProtocol
|
|
6
|
+
) => {
|
|
7
|
+
const fn = (value: SenderMiddlewareOutput) => {
|
|
8
|
+
const isConnected = protocol.isConnected();
|
|
9
|
+
|
|
10
|
+
if (!isConnected && !value.isOptionsRequest) {
|
|
11
|
+
protocol.addPendingSendEntry({
|
|
12
|
+
methodName: fn.displayName,
|
|
13
|
+
lifecycle: SendMiddlewareLifecycle.Prepare,
|
|
14
|
+
...value,
|
|
15
|
+
middlewareContext: {
|
|
16
|
+
...value.middlewareContext,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
value.middlewareContext.minLifecycle = SendMiddlewareLifecycle.Aborted;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return value;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
fn.displayName = 'handleDisconnectedRequest';
|
|
27
|
+
fn.lifecycle = SendMiddlewareLifecycle.Prepare;
|
|
28
|
+
|
|
29
|
+
return fn;
|
|
30
|
+
};
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import isPromise from '@x-oasis/is-promise';
|
|
2
|
+
import { ResponseType, DeserializedMessageOutput } from '../types';
|
|
3
|
+
import AbstractChannelProtocol from '../protocol/AbstractChannelProtocol';
|
|
4
|
+
import { isEventMethod } from '../common';
|
|
5
|
+
import {
|
|
6
|
+
defaultErrorMapper,
|
|
7
|
+
ErrorResponseMapped,
|
|
8
|
+
makeRequest,
|
|
9
|
+
} from '../utils/jsonrpc';
|
|
10
|
+
import { JSONRPCErrorCode } from '../error';
|
|
11
|
+
|
|
12
|
+
export const handlePortRequest =
|
|
13
|
+
(protocol: AbstractChannelProtocol) =>
|
|
14
|
+
(message: DeserializedMessageOutput) => {
|
|
15
|
+
const serviceHost = protocol.service;
|
|
16
|
+
|
|
17
|
+
const { data, event: messageEvent } = message;
|
|
18
|
+
const header = data[0];
|
|
19
|
+
const channelName = header[4];
|
|
20
|
+
|
|
21
|
+
const body = data[1];
|
|
22
|
+
const type = header[0] as any;
|
|
23
|
+
|
|
24
|
+
if (Object.values(ResponseType).includes(type)) {
|
|
25
|
+
return message;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const seqId = header[1];
|
|
29
|
+
const requestPath = header[2];
|
|
30
|
+
const methodName = header[3];
|
|
31
|
+
const args = body[0];
|
|
32
|
+
|
|
33
|
+
if (serviceHost) {
|
|
34
|
+
if (isEventMethod(methodName)) {
|
|
35
|
+
// const event = serviceHost.getHandler(requestPath, methodName)
|
|
36
|
+
// const fn = (...args: any[]) => {
|
|
37
|
+
// const responseHeader = [ResponseType.ReturnSuccess, seqId]
|
|
38
|
+
// let responseBody = []
|
|
39
|
+
// let sendData = null
|
|
40
|
+
// try {
|
|
41
|
+
// responseBody = args
|
|
42
|
+
// sendData = protocol.writeBuffer.encode([responseHeader, responseBody])
|
|
43
|
+
// } catch (err) {
|
|
44
|
+
// sendData = protocol.writeBuffer.encode([responseHeader, []])
|
|
45
|
+
// console.error(`[handleRequest sendReply encode error ] ${requestPath} ${methodName}`, err)
|
|
46
|
+
// }
|
|
47
|
+
|
|
48
|
+
// // TODO: temp; main <=> project renderer...
|
|
49
|
+
// if (messageEvent?.sender) {
|
|
50
|
+
// messageEvent.sender.send(channelName, sendData)
|
|
51
|
+
// return
|
|
52
|
+
// }
|
|
53
|
+
|
|
54
|
+
// protocol.sendReply(sendData)
|
|
55
|
+
// }
|
|
56
|
+
|
|
57
|
+
// event(fn)
|
|
58
|
+
return message;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const handler = serviceHost.getHandler(methodName);
|
|
62
|
+
|
|
63
|
+
// Create JSONRPC request object for error context
|
|
64
|
+
const jsonrpcRequest = makeRequest(seqId, methodName, args);
|
|
65
|
+
|
|
66
|
+
// todo
|
|
67
|
+
const result = Promise.resolve(handler?.(args));
|
|
68
|
+
|
|
69
|
+
if (handler && isPromise(result)) {
|
|
70
|
+
result.then(
|
|
71
|
+
(port: any) => {
|
|
72
|
+
const responseHeader = [ResponseType.PortSuccess, seqId];
|
|
73
|
+
let responseBody: any[] = [];
|
|
74
|
+
let sendData = null;
|
|
75
|
+
try {
|
|
76
|
+
responseBody = [];
|
|
77
|
+
sendData = protocol.writeBuffer.encode([
|
|
78
|
+
responseHeader,
|
|
79
|
+
responseBody,
|
|
80
|
+
]);
|
|
81
|
+
} catch (err) {
|
|
82
|
+
// Encoding error - use standardized error format
|
|
83
|
+
const mapper = defaultErrorMapper(
|
|
84
|
+
err instanceof Error ? err.stack : '',
|
|
85
|
+
JSONRPCErrorCode.InternalError
|
|
86
|
+
);
|
|
87
|
+
const errorResponse = ErrorResponseMapped(
|
|
88
|
+
jsonrpcRequest,
|
|
89
|
+
err,
|
|
90
|
+
mapper
|
|
91
|
+
);
|
|
92
|
+
responseBody = [errorResponse.error];
|
|
93
|
+
sendData = protocol.writeBuffer.encode([
|
|
94
|
+
responseHeader,
|
|
95
|
+
responseBody,
|
|
96
|
+
]);
|
|
97
|
+
console.error(
|
|
98
|
+
`[handleRequest sendReply encode error ] ${requestPath} ${methodName}`,
|
|
99
|
+
err
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// TODO: temp; main <=> project renderer...
|
|
104
|
+
if (messageEvent?.sender) {
|
|
105
|
+
messageEvent.sender.postMessage(channelName, sendData, [port]);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
protocol.sendReply(sendData);
|
|
110
|
+
},
|
|
111
|
+
(err: unknown) => {
|
|
112
|
+
// Use standardized JSONRPC error format
|
|
113
|
+
const mapper = defaultErrorMapper(
|
|
114
|
+
err instanceof Error ? err.stack : '',
|
|
115
|
+
JSONRPCErrorCode.InternalError
|
|
116
|
+
);
|
|
117
|
+
const errorResponse = ErrorResponseMapped(
|
|
118
|
+
jsonrpcRequest,
|
|
119
|
+
err,
|
|
120
|
+
mapper
|
|
121
|
+
);
|
|
122
|
+
const responseHeader = [ResponseType.ReturnFail, seqId];
|
|
123
|
+
const responseBody = [errorResponse.error];
|
|
124
|
+
|
|
125
|
+
if (messageEvent?.sender) {
|
|
126
|
+
messageEvent.sender.send(
|
|
127
|
+
(protocol as any).channelName,
|
|
128
|
+
protocol.writeBuffer.encode([responseHeader, responseBody])
|
|
129
|
+
);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
protocol.sendReply(
|
|
134
|
+
protocol.writeBuffer.encode([responseHeader, responseBody])
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return message;
|
|
141
|
+
};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import isPromise from '@x-oasis/is-promise';
|
|
2
|
+
import { ResponseType, DeserializedMessageOutput } from '../types';
|
|
3
|
+
import AbstractChannelProtocol from '../protocol/AbstractChannelProtocol';
|
|
4
|
+
import {
|
|
5
|
+
ErrorResponseMethodNotFound,
|
|
6
|
+
defaultErrorMapper,
|
|
7
|
+
ErrorResponseMapped,
|
|
8
|
+
makeRequest,
|
|
9
|
+
Request,
|
|
10
|
+
AsyncCallErrorDetail,
|
|
11
|
+
} from '../utils/jsonrpc';
|
|
12
|
+
import { JSONRPCErrorCode } from '../error';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Create standardized error response body
|
|
16
|
+
*/
|
|
17
|
+
const createErrorResponseBody = (
|
|
18
|
+
error: unknown,
|
|
19
|
+
request?: Request
|
|
20
|
+
): {
|
|
21
|
+
code: number;
|
|
22
|
+
message: string;
|
|
23
|
+
data?: AsyncCallErrorDetail;
|
|
24
|
+
} => {
|
|
25
|
+
const mapper = defaultErrorMapper(
|
|
26
|
+
error instanceof Error ? error.stack : '',
|
|
27
|
+
JSONRPCErrorCode.InternalError
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
if (request) {
|
|
31
|
+
const errorResponse = ErrorResponseMapped(request, error, mapper);
|
|
32
|
+
return errorResponse.error;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Fallback when no request context is available
|
|
36
|
+
const { code, message, data } = mapper(error, {} as Request);
|
|
37
|
+
return { code, message, data };
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const handleRequest =
|
|
41
|
+
(protocol: AbstractChannelProtocol) =>
|
|
42
|
+
(message: DeserializedMessageOutput) => {
|
|
43
|
+
const service = protocol.service;
|
|
44
|
+
|
|
45
|
+
const { data } = message;
|
|
46
|
+
const header = data[0];
|
|
47
|
+
|
|
48
|
+
const body = data[1];
|
|
49
|
+
const type = header[0] as any;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* if the message is a response, do nothing and return the message
|
|
53
|
+
*/
|
|
54
|
+
if (Object.values(ResponseType).includes(type)) {
|
|
55
|
+
return message;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const seqId = header[1];
|
|
59
|
+
const requestPath = header[2];
|
|
60
|
+
const methodName = header[3];
|
|
61
|
+
const args = body[0];
|
|
62
|
+
|
|
63
|
+
// Create JSONRPC request object for error context
|
|
64
|
+
const jsonrpcRequest = makeRequest(seqId, methodName, args);
|
|
65
|
+
|
|
66
|
+
const handler = service.getHandler(methodName);
|
|
67
|
+
|
|
68
|
+
// Check if method exists
|
|
69
|
+
if (!handler) {
|
|
70
|
+
const errorResponse = ErrorResponseMethodNotFound(seqId);
|
|
71
|
+
const responseHeader = [ResponseType.ReturnFail, seqId];
|
|
72
|
+
const responseBody = [errorResponse.error];
|
|
73
|
+
|
|
74
|
+
protocol.sendReply(
|
|
75
|
+
protocol.writeBuffer.encode([responseHeader, responseBody])
|
|
76
|
+
);
|
|
77
|
+
return message;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const _result = handler(args);
|
|
81
|
+
|
|
82
|
+
// todo
|
|
83
|
+
const result = Promise.resolve(_result);
|
|
84
|
+
|
|
85
|
+
if (isPromise(result)) {
|
|
86
|
+
result.then(
|
|
87
|
+
(response: any) => {
|
|
88
|
+
const responseHeader = [ResponseType.ReturnSuccess, seqId];
|
|
89
|
+
let responseBody = [];
|
|
90
|
+
let sendData = null;
|
|
91
|
+
try {
|
|
92
|
+
responseBody = [response];
|
|
93
|
+
sendData = protocol.writeBuffer.encode([
|
|
94
|
+
responseHeader,
|
|
95
|
+
responseBody,
|
|
96
|
+
]);
|
|
97
|
+
} catch (err) {
|
|
98
|
+
// Encoding error - use standardized error format
|
|
99
|
+
const errorBody = createErrorResponseBody(err, jsonrpcRequest);
|
|
100
|
+
responseBody = [errorBody];
|
|
101
|
+
sendData = protocol.writeBuffer.encode([
|
|
102
|
+
responseHeader,
|
|
103
|
+
responseBody,
|
|
104
|
+
]);
|
|
105
|
+
console.error(
|
|
106
|
+
`[handleRequest sendReply encode error ] ${requestPath} ${methodName}`,
|
|
107
|
+
err
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
protocol.sendReply(sendData);
|
|
112
|
+
},
|
|
113
|
+
(err: unknown) => {
|
|
114
|
+
// Use standardized JSONRPC error format
|
|
115
|
+
const errorBody = createErrorResponseBody(err, jsonrpcRequest);
|
|
116
|
+
const responseHeader = [ResponseType.ReturnFail, seqId];
|
|
117
|
+
const responseBody = [errorBody];
|
|
118
|
+
|
|
119
|
+
protocol.sendReply(
|
|
120
|
+
protocol.writeBuffer.encode([responseHeader, responseBody])
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
// 其实这儿不应该这么处理,应该返回一个空值,但是为了方便,还是返回原来的消息
|
|
126
|
+
// 因为假如说是一个request的话,到这一步就算处理完了
|
|
127
|
+
return message;
|
|
128
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import AbstractChannelProtocol from '../protocol/AbstractChannelProtocol';
|
|
2
|
+
import { ResponseType } from '../types';
|
|
3
|
+
import RPCService from '../endpoint/RPCService';
|
|
4
|
+
|
|
5
|
+
export const handleAcquirePort = (props: {
|
|
6
|
+
protocol: AbstractChannelProtocol;
|
|
7
|
+
// serviceHost: RPCServiceHost;
|
|
8
|
+
service: RPCService;
|
|
9
|
+
requestPath: string;
|
|
10
|
+
methodName: string;
|
|
11
|
+
seqId: string;
|
|
12
|
+
args: any[];
|
|
13
|
+
}) => {
|
|
14
|
+
const { service, requestPath, methodName, protocol, seqId, args } = props;
|
|
15
|
+
|
|
16
|
+
// const handler = serviceHost.getHandler(requestPath, methodName);
|
|
17
|
+
const handler = service.getHandler(methodName);
|
|
18
|
+
const port = handler?.(args);
|
|
19
|
+
|
|
20
|
+
// 比如port process它监听的是message;你用process创建一个ProcessChannelProtocol
|
|
21
|
+
// 都会触发监听,这个时候并不一定有值返回,其实正常是否考虑将on message这种
|
|
22
|
+
// emitter收敛了,即使你new了,但其实是一个实例
|
|
23
|
+
if (!port) {
|
|
24
|
+
// console.error('may trigger message listener', protocol)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let responseHeader = [ResponseType.PortSuccess, seqId];
|
|
28
|
+
let responseBody: any[] = [];
|
|
29
|
+
let sendData = null;
|
|
30
|
+
try {
|
|
31
|
+
responseBody = [];
|
|
32
|
+
sendData = protocol.writeBuffer.encode([responseHeader, responseBody]);
|
|
33
|
+
} catch (err) {
|
|
34
|
+
responseHeader = [ResponseType.PortFail, seqId];
|
|
35
|
+
sendData = protocol.writeBuffer.encode([responseHeader, []]);
|
|
36
|
+
console.error(
|
|
37
|
+
`[handleRequest sendReply encode error ] ${requestPath} ${methodName}`,
|
|
38
|
+
err
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return port ? [sendData, [port]] : null;
|
|
43
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { RequestType, ResponseType, DeserializedMessageOutput } from '../types';
|
|
2
|
+
import AbstractChannelProtocol from '../protocol/AbstractChannelProtocol';
|
|
3
|
+
|
|
4
|
+
export const handleResponse =
|
|
5
|
+
(protocol: AbstractChannelProtocol) =>
|
|
6
|
+
(message: DeserializedMessageOutput) => {
|
|
7
|
+
if (!message) return message;
|
|
8
|
+
const { data } = message;
|
|
9
|
+
const header = data[0];
|
|
10
|
+
const body = data[1];
|
|
11
|
+
const type = header[0] as any;
|
|
12
|
+
|
|
13
|
+
if (Object.values(RequestType).includes(type)) {
|
|
14
|
+
return message;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const seqId = header[1];
|
|
18
|
+
|
|
19
|
+
const findDefer = protocol.ongoingRequests.get(`${seqId}`);
|
|
20
|
+
|
|
21
|
+
if (findDefer) {
|
|
22
|
+
protocol.ongoingRequests.delete(`${seqId}`);
|
|
23
|
+
if (type === ResponseType.PortSuccess) {
|
|
24
|
+
findDefer.resolve(message.ports[0]);
|
|
25
|
+
} else if (type === ResponseType.ReturnFail) {
|
|
26
|
+
findDefer.reject(body[0]);
|
|
27
|
+
} else findDefer.resolve(body[0]);
|
|
28
|
+
} else {
|
|
29
|
+
const findListener = protocol.requestEvents.get(`${seqId}`);
|
|
30
|
+
|
|
31
|
+
if (findListener) {
|
|
32
|
+
findListener(...body);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export * from './buffer';
|
|
2
|
+
// export * from './handleRequest';
|
|
3
|
+
export * from './normalize';
|
|
4
|
+
export * from './handleResponse';
|
|
5
|
+
export * from './prepareRequestData';
|
|
6
|
+
export * from './updateSeqInfo';
|
|
7
|
+
// export * from './handlePortRequest';
|
|
8
|
+
export * from './sendRequest';
|
|
9
|
+
// export * from './handleDisconnectedRequest';
|
|
10
|
+
|
|
11
|
+
export { runMiddlewares } from './utils';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import AbstractChannelProtocol from '../protocol/AbstractChannelProtocol';
|
|
2
|
+
import { NormalizedRawMessageOutput } from '../types';
|
|
3
|
+
|
|
4
|
+
export const createSenderLogger =
|
|
5
|
+
(logService: any) =>
|
|
6
|
+
(channel: AbstractChannelProtocol) =>
|
|
7
|
+
(value: NormalizedRawMessageOutput) => {
|
|
8
|
+
logService.info(`${channel.masterProcessName} send message`, value.data);
|
|
9
|
+
return value;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const createClientLogger =
|
|
13
|
+
(logService: any) =>
|
|
14
|
+
(channel: AbstractChannelProtocol) =>
|
|
15
|
+
(value: NormalizedRawMessageOutput) => {
|
|
16
|
+
const { data } = value;
|
|
17
|
+
logService.info(
|
|
18
|
+
`${channel.masterProcessName} receive message from ${channel.description}`,
|
|
19
|
+
data
|
|
20
|
+
);
|
|
21
|
+
return value;
|
|
22
|
+
};
|