@opensumi/ide-connection 2.27.3-rc-1708399099.0 → 2.27.3-rc-1710489030.0
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 +1 -1
- package/lib/browser/ws-channel-handler.d.ts +1 -1
- package/lib/browser/ws-channel-handler.d.ts.map +1 -1
- package/lib/browser/ws-channel-handler.js +23 -33
- package/lib/browser/ws-channel-handler.js.map +1 -1
- package/lib/common/buffers/buffers.d.ts +1 -0
- package/lib/common/buffers/buffers.d.ts.map +1 -1
- package/lib/common/buffers/buffers.js +3 -3
- package/lib/common/buffers/buffers.js.map +1 -1
- package/lib/common/{utils.d.ts → capturer.d.ts} +1 -19
- package/lib/common/capturer.d.ts.map +1 -0
- package/lib/common/capturer.js +26 -0
- package/lib/common/capturer.js.map +1 -0
- package/lib/common/connection/drivers/frame-decoder.d.ts +40 -1
- package/lib/common/connection/drivers/frame-decoder.d.ts.map +1 -1
- package/lib/common/connection/drivers/frame-decoder.js +9 -10
- package/lib/common/connection/drivers/frame-decoder.js.map +1 -1
- package/lib/common/connection/drivers/index.d.ts +0 -1
- package/lib/common/connection/drivers/index.d.ts.map +1 -1
- package/lib/common/connection/drivers/index.js +0 -1
- package/lib/common/connection/drivers/index.js.map +1 -1
- package/lib/common/connection/drivers/message-port.d.ts.map +1 -1
- package/lib/common/connection/drivers/message-port.js +1 -4
- package/lib/common/connection/drivers/message-port.js.map +1 -1
- package/lib/common/connection/drivers/node-message-port.d.ts +1 -1
- package/lib/common/connection/drivers/node-message-port.d.ts.map +1 -1
- package/lib/common/connection/drivers/node-message-port.js.map +1 -1
- package/lib/common/connection/drivers/reconnecting-websocket.d.ts.map +1 -1
- package/lib/common/connection/drivers/reconnecting-websocket.js +1 -1
- package/lib/common/connection/drivers/reconnecting-websocket.js.map +1 -1
- package/lib/common/connection/drivers/socket.d.ts +3 -10
- package/lib/common/connection/drivers/socket.d.ts.map +1 -1
- package/lib/common/connection/drivers/socket.js +3 -36
- package/lib/common/connection/drivers/socket.js.map +1 -1
- package/lib/common/connection/drivers/stream.d.ts +17 -0
- package/lib/common/connection/drivers/stream.d.ts.map +1 -0
- package/lib/common/connection/drivers/stream.js +70 -0
- package/lib/common/connection/drivers/stream.js.map +1 -0
- package/lib/common/connection/drivers/ws-websocket.d.ts +1 -1
- package/lib/common/connection/drivers/ws-websocket.d.ts.map +1 -1
- package/lib/common/connection/drivers/ws-websocket.js.map +1 -1
- package/lib/common/fury-extends/any.d.ts +10 -7
- package/lib/common/fury-extends/any.d.ts.map +1 -1
- package/lib/common/fury-extends/any.js +126 -105
- package/lib/common/fury-extends/any.js.map +1 -1
- package/lib/common/fury-extends/one-of.d.ts +10 -5
- package/lib/common/fury-extends/one-of.d.ts.map +1 -1
- package/lib/common/fury-extends/one-of.js +65 -30
- package/lib/common/fury-extends/one-of.js.map +1 -1
- package/lib/common/fury-extends/shared.d.ts +2 -0
- package/lib/common/fury-extends/shared.d.ts.map +1 -1
- package/lib/common/fury-extends/shared.js.map +1 -1
- package/lib/common/index.d.ts +2 -2
- package/lib/common/index.d.ts.map +1 -1
- package/lib/common/index.js +2 -2
- package/lib/common/index.js.map +1 -1
- package/lib/common/message.d.ts +1 -1
- package/lib/common/message.d.ts.map +1 -1
- package/lib/common/rpc/connection.d.ts +31 -15
- package/lib/common/rpc/connection.d.ts.map +1 -1
- package/lib/common/rpc/connection.js +206 -138
- package/lib/common/rpc/connection.js.map +1 -1
- package/lib/common/rpc/index.d.ts +1 -1
- package/lib/common/rpc/index.d.ts.map +1 -1
- package/lib/common/rpc/index.js +1 -1
- package/lib/common/rpc/index.js.map +1 -1
- package/lib/common/rpc/message-io.d.ts +61 -0
- package/lib/common/rpc/message-io.d.ts.map +1 -0
- package/lib/common/rpc/message-io.js +159 -0
- package/lib/common/rpc/message-io.js.map +1 -0
- package/lib/common/rpc/multiplexer.d.ts +3 -0
- package/lib/common/rpc/multiplexer.d.ts.map +1 -1
- package/lib/common/rpc/multiplexer.js +3 -0
- package/lib/common/rpc/multiplexer.js.map +1 -1
- package/lib/common/rpc/types.d.ts +26 -5
- package/lib/common/rpc/types.d.ts.map +1 -1
- package/lib/common/rpc-service/center.d.ts +6 -3
- package/lib/common/rpc-service/center.d.ts.map +1 -1
- package/lib/common/rpc-service/center.js +39 -31
- package/lib/common/rpc-service/center.js.map +1 -1
- package/lib/common/rpc-service/proxy/base.d.ts +5 -3
- package/lib/common/rpc-service/proxy/base.d.ts.map +1 -1
- package/lib/common/rpc-service/proxy/base.js +56 -17
- package/lib/common/rpc-service/proxy/base.js.map +1 -1
- package/lib/common/rpc-service/proxy/index.d.ts +1 -3
- package/lib/common/rpc-service/proxy/index.d.ts.map +1 -1
- package/lib/common/rpc-service/proxy/index.js +1 -3
- package/lib/common/rpc-service/proxy/index.js.map +1 -1
- package/lib/common/rpc-service/proxy/{legacy.d.ts → json.d.ts} +5 -5
- package/lib/common/rpc-service/proxy/json.d.ts.map +1 -0
- package/lib/common/rpc-service/proxy/{legacy.js → json.js} +46 -56
- package/lib/common/rpc-service/proxy/json.js.map +1 -0
- package/lib/common/rpc-service/proxy/sumi.d.ts +1 -1
- package/lib/common/rpc-service/proxy/sumi.d.ts.map +1 -1
- package/lib/common/rpc-service/proxy/sumi.js +25 -37
- package/lib/common/rpc-service/proxy/sumi.js.map +1 -1
- package/lib/common/rpc-service/{proxy/registry.d.ts → registry.d.ts} +12 -1
- package/lib/common/rpc-service/registry.d.ts.map +1 -0
- package/lib/common/rpc-service/registry.js +99 -0
- package/lib/common/rpc-service/registry.js.map +1 -0
- package/lib/common/rpc-service/stub.js +4 -6
- package/lib/common/rpc-service/stub.js.map +1 -1
- package/lib/common/{ext-rpc-protocol.d.ts → rpcProtocol.d.ts} +2 -2
- package/lib/common/rpcProtocol.d.ts.map +1 -0
- package/lib/common/{ext-rpc-protocol.js → rpcProtocol.js} +5 -6
- package/lib/common/rpcProtocol.js.map +1 -0
- package/lib/common/server-handler.d.ts +35 -0
- package/lib/common/server-handler.d.ts.map +1 -0
- package/lib/common/server-handler.js +165 -0
- package/lib/common/server-handler.js.map +1 -0
- package/lib/common/types.d.ts +14 -0
- package/lib/common/types.d.ts.map +1 -1
- package/lib/common/ws-channel.d.ts +6 -10
- package/lib/common/ws-channel.d.ts.map +1 -1
- package/lib/common/ws-channel.js +16 -15
- package/lib/common/ws-channel.js.map +1 -1
- package/lib/electron/channel-handler.d.ts +14 -0
- package/lib/electron/channel-handler.d.ts.map +1 -0
- package/lib/electron/channel-handler.js +26 -0
- package/lib/electron/channel-handler.js.map +1 -0
- package/lib/electron/index.d.ts +2 -0
- package/lib/electron/index.d.ts.map +1 -0
- package/lib/electron/index.js +5 -0
- package/lib/electron/index.js.map +1 -0
- package/lib/node/common-channel-handler.d.ts +6 -25
- package/lib/node/common-channel-handler.d.ts.map +1 -1
- package/lib/node/common-channel-handler.js +9 -151
- package/lib/node/common-channel-handler.js.map +1 -1
- package/package.json +5 -5
- package/src/browser/ws-channel-handler.ts +26 -40
- package/src/common/buffers/buffers.ts +1 -1
- package/src/common/capturer.ts +36 -0
- package/src/common/connection/drivers/frame-decoder.ts +11 -11
- package/src/common/connection/drivers/index.ts +0 -1
- package/src/common/connection/drivers/message-port.ts +1 -4
- package/src/common/connection/drivers/node-message-port.ts +2 -2
- package/src/common/connection/drivers/reconnecting-websocket.ts +3 -2
- package/src/common/connection/drivers/socket.ts +4 -42
- package/src/common/connection/drivers/stream.ts +76 -0
- package/src/common/connection/drivers/ws-websocket.ts +2 -2
- package/src/common/fury-extends/any.ts +122 -102
- package/src/common/fury-extends/one-of.ts +79 -31
- package/src/common/fury-extends/shared.ts +3 -0
- package/src/common/index.ts +2 -2
- package/src/common/message.ts +1 -1
- package/src/common/rpc/connection.ts +228 -166
- package/src/common/rpc/index.ts +1 -1
- package/src/common/rpc/message-io.ts +223 -0
- package/src/common/rpc/multiplexer.ts +3 -0
- package/src/common/rpc/types.ts +30 -5
- package/src/common/rpc-service/center.ts +37 -31
- package/src/common/rpc-service/proxy/base.ts +59 -12
- package/src/common/rpc-service/proxy/index.ts +1 -3
- package/src/common/rpc-service/proxy/{legacy.ts → json.ts} +47 -57
- package/src/common/rpc-service/proxy/sumi.ts +23 -35
- package/src/common/rpc-service/registry.ts +125 -0
- package/src/common/rpc-service/stub.ts +6 -6
- package/src/common/{ext-rpc-protocol.ts → rpcProtocol.ts} +2 -2
- package/src/common/server-handler.ts +183 -0
- package/src/common/types.ts +13 -0
- package/src/common/ws-channel.ts +21 -23
- package/src/electron/channel-handler.ts +26 -0
- package/src/electron/index.ts +1 -0
- package/src/node/common-channel-handler.ts +10 -165
- package/lib/common/connection/drivers/utils.d.ts +0 -12
- package/lib/common/connection/drivers/utils.d.ts.map +0 -1
- package/lib/common/connection/drivers/utils.js +0 -49
- package/lib/common/connection/drivers/utils.js.map +0 -1
- package/lib/common/ext-rpc-protocol.d.ts.map +0 -1
- package/lib/common/ext-rpc-protocol.js.map +0 -1
- package/lib/common/rpc/packet.d.ts +0 -65
- package/lib/common/rpc/packet.d.ts.map +0 -1
- package/lib/common/rpc/packet.js +0 -82
- package/lib/common/rpc/packet.js.map +0 -1
- package/lib/common/rpc/protocol-repository.d.ts +0 -32
- package/lib/common/rpc/protocol-repository.d.ts.map +0 -1
- package/lib/common/rpc/protocol-repository.js +0 -118
- package/lib/common/rpc/protocol-repository.js.map +0 -1
- package/lib/common/rpc/utils.d.ts +0 -2
- package/lib/common/rpc/utils.d.ts.map +0 -1
- package/lib/common/rpc/utils.js +0 -10
- package/lib/common/rpc/utils.js.map +0 -1
- package/lib/common/rpc-service/proxy/invoker.d.ts +0 -14
- package/lib/common/rpc-service/proxy/invoker.d.ts.map +0 -1
- package/lib/common/rpc-service/proxy/invoker.js +0 -34
- package/lib/common/rpc-service/proxy/invoker.js.map +0 -1
- package/lib/common/rpc-service/proxy/legacy.d.ts.map +0 -1
- package/lib/common/rpc-service/proxy/legacy.js.map +0 -1
- package/lib/common/rpc-service/proxy/registry.d.ts.map +0 -1
- package/lib/common/rpc-service/proxy/registry.js +0 -46
- package/lib/common/rpc-service/proxy/registry.js.map +0 -1
- package/lib/common/utils.d.ts.map +0 -1
- package/lib/common/utils.js +0 -57
- package/lib/common/utils.js.map +0 -1
- package/src/common/connection/drivers/utils.ts +0 -52
- package/src/common/rpc/packet.ts +0 -104
- package/src/common/rpc/protocol-repository.ts +0 -180
- package/src/common/rpc/utils.ts +0 -5
- package/src/common/rpc-service/proxy/invoker.ts +0 -45
- package/src/common/rpc-service/proxy/registry.ts +0 -56
- package/src/common/utils.ts +0 -80
|
@@ -9,8 +9,8 @@ interface IRPCResult {
|
|
|
9
9
|
data: any;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
export class
|
|
13
|
-
protected engine = '
|
|
12
|
+
export class ProxyJson extends ProxyBase<MessageConnection> {
|
|
13
|
+
protected engine = 'json' as const;
|
|
14
14
|
|
|
15
15
|
protected bindMethods(methods: string[]): void {
|
|
16
16
|
for (const method of methods) {
|
|
@@ -53,68 +53,58 @@ export class ProxyLegacy extends ProxyBase<MessageConnection> {
|
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (result.error) {
|
|
94
|
-
const error = new Error(result.data.message);
|
|
95
|
-
if (result.data.stack) {
|
|
96
|
-
error.stack = result.data.stack;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
this.captureSendRequestFail(requestId, prop, result.data);
|
|
100
|
-
throw error;
|
|
101
|
-
} else {
|
|
102
|
-
this.captureSendRequestResult(requestId, prop, result.data);
|
|
103
|
-
return result.data;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
};
|
|
56
|
+
async invoke(prop: string, ...args: any[]): Promise<any> {
|
|
57
|
+
await this.connectionPromise.promise;
|
|
58
|
+
|
|
59
|
+
let isSingleArray = false;
|
|
60
|
+
if (args.length === 1 && Array.isArray(args[0])) {
|
|
61
|
+
isSingleArray = true;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 调用方法为 on 开头时,作为单项通知
|
|
65
|
+
if (prop.startsWith('on')) {
|
|
66
|
+
this.captureSendNotification(prop, args);
|
|
67
|
+
if (isSingleArray) {
|
|
68
|
+
this.connection.sendNotification(prop, [...args]);
|
|
69
|
+
} else {
|
|
70
|
+
this.connection.sendNotification(prop, ...args);
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
// generate a unique requestId to associate request and requestResult
|
|
74
|
+
const requestId = this.nextRequestId();
|
|
75
|
+
|
|
76
|
+
let requestResult: Promise<any>;
|
|
77
|
+
|
|
78
|
+
if (isSingleArray) {
|
|
79
|
+
requestResult = this.connection.sendRequest(prop, [...args]) as Promise<any>;
|
|
80
|
+
} else {
|
|
81
|
+
requestResult = this.connection.sendRequest(prop, ...args) as Promise<any>;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
this.captureSendRequest(requestId, prop, args);
|
|
85
|
+
|
|
86
|
+
const result: IRPCResult = await requestResult;
|
|
87
|
+
|
|
88
|
+
if (result.error) {
|
|
89
|
+
const error = new Error(result.data.message);
|
|
90
|
+
if (result.data.stack) {
|
|
91
|
+
error.stack = result.data.stack;
|
|
107
92
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
93
|
+
|
|
94
|
+
this.captureSendRequestFail(requestId, prop, result.data);
|
|
95
|
+
throw error;
|
|
96
|
+
} else {
|
|
97
|
+
this.captureSendRequestResult(requestId, prop, result.data);
|
|
98
|
+
return result.data;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
111
101
|
}
|
|
112
102
|
|
|
113
103
|
/**
|
|
114
104
|
* 对于纯数组参数的情况,收到请求/通知后做展开操作
|
|
115
105
|
* 因为在通信层会为每个 rpc 调用添加一个 CancellationToken 参数
|
|
116
106
|
* 如果参数本身是数组, 在方法中如果使用 spread 运算符获取参数(...args),则会出现 [...args, MutableToken] 这种情况
|
|
117
|
-
* 所以发送请求时将这类参数统一再用数组包了一层,形如 [[...args]], 参考 {@link
|
|
107
|
+
* 所以发送请求时将这类参数统一再用数组包了一层,形如 [[...args]], 参考 {@link ProxyJson.get get} 方法
|
|
118
108
|
* 此时接收到的数组类参数固定长度为 2,且最后一项一定是 MutableToken
|
|
119
109
|
* @param args
|
|
120
110
|
* @returns args
|
|
@@ -35,47 +35,35 @@ export class ProxySumi extends ProxyBase<SumiConnection> {
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
get: (target: any, p: PropertyKey) => {
|
|
41
|
-
if (!target[p]) {
|
|
42
|
-
target[p] = async (...args: any[]) => {
|
|
43
|
-
await this.connectionPromise.promise;
|
|
44
|
-
const prop = p.toString();
|
|
38
|
+
async invoke(prop: string, ...args: any[]): Promise<any> {
|
|
39
|
+
await this.connectionPromise.promise;
|
|
45
40
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
return target[p];
|
|
66
|
-
},
|
|
67
|
-
});
|
|
41
|
+
// 调用方法为 on 开头时,作为单项通知
|
|
42
|
+
if (prop.startsWith('on')) {
|
|
43
|
+
this.captureSendNotification(prop, args);
|
|
44
|
+
this.connection.sendNotification(prop, ...args);
|
|
45
|
+
} else {
|
|
46
|
+
// generate a unique requestId to associate request and requestResult
|
|
47
|
+
const requestId = this.nextRequestId();
|
|
48
|
+
this.captureSendRequest(requestId, prop, args);
|
|
49
|
+
try {
|
|
50
|
+
const result = await this.connection.sendRequest(prop, ...args);
|
|
51
|
+
this.captureSendRequestResult(requestId, prop, result);
|
|
52
|
+
return result;
|
|
53
|
+
} catch (error) {
|
|
54
|
+
this.captureSendRequestFail(requestId, prop, error);
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
68
58
|
}
|
|
69
59
|
|
|
70
60
|
listen(connection: SumiConnection): void {
|
|
71
61
|
super.listen(connection);
|
|
72
62
|
connection.onRequestNotFound((method) => {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
throw METHOD_NOT_REGISTERED;
|
|
78
|
-
}
|
|
63
|
+
const requestId = this.nextRequestId();
|
|
64
|
+
this.captureOnRequest(requestId, method, []);
|
|
65
|
+
this.captureOnRequestFail(requestId, method, METHOD_NOT_REGISTERED);
|
|
66
|
+
throw METHOD_NOT_REGISTERED;
|
|
79
67
|
});
|
|
80
68
|
}
|
|
81
69
|
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { Emitter } from '@opensumi/ide-core-common';
|
|
2
|
+
|
|
3
|
+
import { MessageIO, TSumiProtocol, TSumiProtocolMethod } from '../rpc';
|
|
4
|
+
import { RPCServiceMethod } from '../types';
|
|
5
|
+
|
|
6
|
+
export function getServiceMethods(service: any): string[] {
|
|
7
|
+
let props: any[] = [];
|
|
8
|
+
|
|
9
|
+
if (/^\s*class/.test(service.constructor.toString())) {
|
|
10
|
+
let obj = service;
|
|
11
|
+
do {
|
|
12
|
+
props = props.concat(Object.getOwnPropertyNames(obj));
|
|
13
|
+
} while ((obj = Object.getPrototypeOf(obj)));
|
|
14
|
+
props = props.sort().filter((e, i, arr) => e !== arr[i + 1] && typeof service[e] === 'function');
|
|
15
|
+
} else {
|
|
16
|
+
for (const prop in service) {
|
|
17
|
+
if (service[prop] && typeof service[prop] === 'function') {
|
|
18
|
+
props.push(prop);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return props;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Store all executable services
|
|
28
|
+
*/
|
|
29
|
+
export class ServiceRegistry {
|
|
30
|
+
protected emitter = new Emitter<string[]>();
|
|
31
|
+
|
|
32
|
+
private serviceMethodMap = new Map<PropertyKey, RPCServiceMethod>();
|
|
33
|
+
|
|
34
|
+
onServicesUpdate = this.emitter.event;
|
|
35
|
+
|
|
36
|
+
register(name: string, methodFn: RPCServiceMethod) {
|
|
37
|
+
this.serviceMethodMap.set(name, methodFn);
|
|
38
|
+
this.emitter.fire([name]);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
registerService(
|
|
42
|
+
service: any,
|
|
43
|
+
options?: {
|
|
44
|
+
nameConverter?: (str: string) => string;
|
|
45
|
+
},
|
|
46
|
+
) {
|
|
47
|
+
const serviceNames = [] as string[];
|
|
48
|
+
const { nameConverter } = options || {};
|
|
49
|
+
const methods = getServiceMethods(service);
|
|
50
|
+
for (const method of methods) {
|
|
51
|
+
let methodName = method;
|
|
52
|
+
if (nameConverter) {
|
|
53
|
+
methodName = nameConverter(method);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
this.serviceMethodMap.set(methodName, service[method].bind(service));
|
|
57
|
+
serviceNames.push(methodName);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
this.emitter.fire(serviceNames);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
has(name: PropertyKey) {
|
|
64
|
+
return this.serviceMethodMap.has(name);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
invoke(name: PropertyKey, ...args: any[]): any {
|
|
68
|
+
// here because we have checked the existence of the method
|
|
69
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
70
|
+
return this.serviceMethodMap.get(name)!(...args);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
methods() {
|
|
74
|
+
return Array.from(this.serviceMethodMap.keys());
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export class ProtocolRegistry {
|
|
79
|
+
protected emitter = new Emitter<string[]>();
|
|
80
|
+
|
|
81
|
+
private protocolMap = new Map<PropertyKey, TSumiProtocolMethod>();
|
|
82
|
+
|
|
83
|
+
onProtocolUpdate = this.emitter.event;
|
|
84
|
+
|
|
85
|
+
addProtocol(
|
|
86
|
+
protocol: TSumiProtocol,
|
|
87
|
+
options?: {
|
|
88
|
+
nameConverter?: (str: string) => string;
|
|
89
|
+
},
|
|
90
|
+
) {
|
|
91
|
+
const serviceNames = [] as string[];
|
|
92
|
+
const { nameConverter } = options || {};
|
|
93
|
+
const { methods } = protocol;
|
|
94
|
+
|
|
95
|
+
for (const proto of methods) {
|
|
96
|
+
let method = proto.method;
|
|
97
|
+
if (nameConverter) {
|
|
98
|
+
method = nameConverter(method);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
this.protocolMap.set(method, {
|
|
102
|
+
...proto,
|
|
103
|
+
method,
|
|
104
|
+
});
|
|
105
|
+
serviceNames.push(method);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
this.emitter.fire(serviceNames);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
applyTo(io: MessageIO) {
|
|
112
|
+
for (const protocol of this.protocolMap.values()) {
|
|
113
|
+
io.loadProtocolMethod(protocol);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
this.onProtocolUpdate((methods) => {
|
|
117
|
+
for (const method of methods) {
|
|
118
|
+
const protocol = this.protocolMap.get(method);
|
|
119
|
+
if (protocol) {
|
|
120
|
+
io.loadProtocolMethod(protocol);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -27,16 +27,16 @@ export class RPCServiceStub {
|
|
|
27
27
|
new Proxy<T extends void ? RPCServiceStub : RPCServiceStub & T>(this as any, {
|
|
28
28
|
// 调用方
|
|
29
29
|
get: (target, prop: string) => {
|
|
30
|
-
if (
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
30
|
+
if (typeof prop === 'symbol') {
|
|
31
|
+
return Promise.resolve();
|
|
32
|
+
}
|
|
34
33
|
|
|
34
|
+
if (!target[prop]) {
|
|
35
35
|
target[prop] = (...args: any[]) => this.broadcast(prop, ...args);
|
|
36
36
|
return target[prop];
|
|
37
|
-
} else {
|
|
38
|
-
return target[prop];
|
|
39
37
|
}
|
|
38
|
+
|
|
39
|
+
return target[prop];
|
|
40
40
|
},
|
|
41
41
|
});
|
|
42
42
|
}
|
|
@@ -22,7 +22,7 @@ export interface IProxyIdentifier {
|
|
|
22
22
|
countId: number;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
export {
|
|
25
|
+
export { IRPCProtocol, ProxyIdentifier };
|
|
26
26
|
|
|
27
27
|
export function createExtHostContextProxyIdentifier<T>(serviceId: string): ProxyIdentifier<T> {
|
|
28
28
|
const identifier = new ProxyIdentifier<T>(serviceId);
|
|
@@ -199,7 +199,7 @@ export class RPCProtocol implements IRPCProtocol {
|
|
|
199
199
|
this._lastMessageId = 0;
|
|
200
200
|
this.logger = logger || console;
|
|
201
201
|
this.logger.error(
|
|
202
|
-
"You are using the deprecated 'RPCProtocol'
|
|
202
|
+
"You are using the deprecated class: 'RPCProtocol'. Please use the new one: 'SumiConnectionMultiplexer'",
|
|
203
203
|
);
|
|
204
204
|
this._protocol.onMessage((msg) => this._receiveOneMessage(msg));
|
|
205
205
|
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { IConnectionShape } from './connection/types';
|
|
2
|
+
import { ILogger } from './types';
|
|
3
|
+
import { ChannelMessage, WSChannel, parse, pongMessage } from './ws-channel';
|
|
4
|
+
|
|
5
|
+
export interface IPathHandler {
|
|
6
|
+
dispose: (channel: WSChannel, connectionId: string) => void;
|
|
7
|
+
handler: (channel: WSChannel, connectionId: string, params?: Record<string, string>) => void;
|
|
8
|
+
reconnect?: (channel: WSChannel, connectionId: string) => void;
|
|
9
|
+
connection?: any;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class CommonChannelPathHandler {
|
|
13
|
+
private handlerMap: Map<string, IPathHandler[]> = new Map();
|
|
14
|
+
private paramsKey: Map<string, string> = new Map();
|
|
15
|
+
|
|
16
|
+
register(channelPath: string, handler: IPathHandler) {
|
|
17
|
+
const paramsIndex = channelPath.indexOf('/:');
|
|
18
|
+
const hasParams = paramsIndex >= 0;
|
|
19
|
+
let channelToken = channelPath;
|
|
20
|
+
if (hasParams) {
|
|
21
|
+
channelToken = channelPath.slice(0, paramsIndex);
|
|
22
|
+
this.paramsKey.set(channelToken, channelPath.slice(paramsIndex + 2));
|
|
23
|
+
}
|
|
24
|
+
if (!this.handlerMap.has(channelToken)) {
|
|
25
|
+
this.handlerMap.set(channelToken, []);
|
|
26
|
+
}
|
|
27
|
+
const handlerArr = this.handlerMap.get(channelToken) as IPathHandler[];
|
|
28
|
+
const handlerFn = handler.handler.bind(handler);
|
|
29
|
+
const setHandler = (channel: WSChannel, clientId: string, params: any) => {
|
|
30
|
+
handler.connection = channel;
|
|
31
|
+
handlerFn(channel, clientId, params);
|
|
32
|
+
};
|
|
33
|
+
handler.handler = setHandler;
|
|
34
|
+
handlerArr.push(handler);
|
|
35
|
+
this.handlerMap.set(channelToken, handlerArr);
|
|
36
|
+
}
|
|
37
|
+
getParams(channelPath: string, value: string): Record<string, string> {
|
|
38
|
+
const params = {} as Record<string, string>;
|
|
39
|
+
if (this.paramsKey.has(channelPath)) {
|
|
40
|
+
const key = this.paramsKey.get(channelPath);
|
|
41
|
+
if (key) {
|
|
42
|
+
params[key] = value;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return params;
|
|
46
|
+
}
|
|
47
|
+
removeHandler(channelPath: string, handler: IPathHandler) {
|
|
48
|
+
const paramsIndex = channelPath.indexOf(':');
|
|
49
|
+
const hasParams = paramsIndex >= 0;
|
|
50
|
+
let channelToken = channelPath;
|
|
51
|
+
if (hasParams) {
|
|
52
|
+
channelToken = channelPath.slice(0, paramsIndex);
|
|
53
|
+
}
|
|
54
|
+
const handlerArr = this.handlerMap.get(channelToken) || [];
|
|
55
|
+
const removeIndex = handlerArr.indexOf(handler);
|
|
56
|
+
if (removeIndex !== -1) {
|
|
57
|
+
handlerArr.splice(removeIndex, 1);
|
|
58
|
+
}
|
|
59
|
+
this.handlerMap.set(channelPath, handlerArr);
|
|
60
|
+
}
|
|
61
|
+
get(channelPath: string) {
|
|
62
|
+
return this.handlerMap.get(channelPath);
|
|
63
|
+
}
|
|
64
|
+
disposeConnectionClientId(channel: any, clientId: string) {
|
|
65
|
+
this.handlerMap.forEach((handlerArr: IPathHandler[]) => {
|
|
66
|
+
handlerArr.forEach((handler: IPathHandler) => {
|
|
67
|
+
handler.dispose(channel, clientId);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
dispatchChannelOpen(path: string, channel: WSChannel, clientId: string) {
|
|
72
|
+
// 根据 path 拿到注册的 handler
|
|
73
|
+
let handlerArr = this.get(path);
|
|
74
|
+
let params: Record<string, string> | undefined;
|
|
75
|
+
// 尝试通过父路径查找处理函数,如server/:id方式注册的handler
|
|
76
|
+
if (!handlerArr) {
|
|
77
|
+
const slashIndex = path.indexOf('/');
|
|
78
|
+
const hasSlash = slashIndex >= 0;
|
|
79
|
+
if (hasSlash) {
|
|
80
|
+
handlerArr = this.get(path.slice(0, slashIndex));
|
|
81
|
+
params = this.getParams(path.slice(0, slashIndex), path.slice(slashIndex + 1));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (handlerArr) {
|
|
86
|
+
for (let i = 0, len = handlerArr.length; i < len; i++) {
|
|
87
|
+
const handler = handlerArr[i];
|
|
88
|
+
handler.handler(channel, clientId, params);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
getAll() {
|
|
94
|
+
return Array.from(this.handlerMap.values());
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export const commonChannelPathHandler = new CommonChannelPathHandler();
|
|
99
|
+
|
|
100
|
+
export abstract class BaseCommonChannelHandler {
|
|
101
|
+
protected channelMap: Map<string, WSChannel> = new Map();
|
|
102
|
+
|
|
103
|
+
heartbeatTimer: NodeJS.Timeout | null = null;
|
|
104
|
+
|
|
105
|
+
constructor(public handlerId: string, protected logger: ILogger = console) {}
|
|
106
|
+
|
|
107
|
+
abstract doHeartbeat(connection: any): void;
|
|
108
|
+
|
|
109
|
+
private heartbeat(connection: any) {
|
|
110
|
+
const timer = global.setTimeout(() => {
|
|
111
|
+
this.doHeartbeat(connection);
|
|
112
|
+
this.heartbeat(connection);
|
|
113
|
+
}, 5000);
|
|
114
|
+
|
|
115
|
+
if (this.heartbeatTimer) {
|
|
116
|
+
clearTimeout(this.heartbeatTimer);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
this.heartbeatTimer = timer;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
receiveConnection(connection: IConnectionShape<Uint8Array>) {
|
|
123
|
+
let clientId: string;
|
|
124
|
+
this.heartbeat(connection);
|
|
125
|
+
|
|
126
|
+
connection.onMessage((data: Uint8Array) => {
|
|
127
|
+
let msg: ChannelMessage;
|
|
128
|
+
try {
|
|
129
|
+
msg = parse(data);
|
|
130
|
+
|
|
131
|
+
switch (msg.kind) {
|
|
132
|
+
case 'ping':
|
|
133
|
+
connection.send(pongMessage);
|
|
134
|
+
break;
|
|
135
|
+
case 'open': {
|
|
136
|
+
const { id, path } = msg;
|
|
137
|
+
clientId = msg.clientId;
|
|
138
|
+
this.logger.log(`open a new connection channel ${clientId} with path ${path}`);
|
|
139
|
+
|
|
140
|
+
const channel = new WSChannel(connection, { id, logger: this.logger });
|
|
141
|
+
this.channelMap.set(id, channel);
|
|
142
|
+
|
|
143
|
+
commonChannelPathHandler.dispatchChannelOpen(path, channel, clientId);
|
|
144
|
+
channel.serverReady();
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
default: {
|
|
148
|
+
const { id } = msg;
|
|
149
|
+
const channel = this.channelMap.get(id);
|
|
150
|
+
if (channel) {
|
|
151
|
+
channel.dispatchChannelMessage(msg);
|
|
152
|
+
} else {
|
|
153
|
+
this.logger.warn(`channel ${id} is not found`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
} catch (e) {
|
|
158
|
+
this.logger.error('handle connection message error', e);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
connection.onceClose(() => {
|
|
163
|
+
commonChannelPathHandler.disposeConnectionClientId(connection, clientId);
|
|
164
|
+
|
|
165
|
+
Array.from(this.channelMap.values())
|
|
166
|
+
.filter((channel) => channel.id.toString().indexOf(clientId) !== -1)
|
|
167
|
+
.forEach((channel) => {
|
|
168
|
+
channel.close(1, 'close');
|
|
169
|
+
channel.dispose();
|
|
170
|
+
this.channelMap.delete(channel.id);
|
|
171
|
+
this.logger.log(`Remove connection channel ${channel.id}`);
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
dispose() {
|
|
177
|
+
if (this.heartbeatTimer) {
|
|
178
|
+
clearTimeout(this.heartbeatTimer);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export const RPCServiceChannelPath = 'RPCService';
|
package/src/common/types.ts
CHANGED
|
@@ -15,3 +15,16 @@ export enum ServiceType {
|
|
|
15
15
|
export interface IBench {
|
|
16
16
|
registerService: (service: string) => void;
|
|
17
17
|
}
|
|
18
|
+
|
|
19
|
+
export interface WSCloseInfo {
|
|
20
|
+
channelPath: string;
|
|
21
|
+
closeEvent: { code: number; reason: string };
|
|
22
|
+
connectInfo: ConnectionInfo;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface ConnectionInfo {
|
|
26
|
+
type: string;
|
|
27
|
+
downlink: number;
|
|
28
|
+
uplink: number;
|
|
29
|
+
rtt: number;
|
|
30
|
+
}
|
package/src/common/ws-channel.ts
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
import type net from 'net';
|
|
2
|
-
|
|
3
1
|
import { Type } from '@furyjs/fury';
|
|
4
|
-
import type WebSocket from 'ws';
|
|
5
2
|
|
|
6
3
|
import { EventEmitter } from '@opensumi/events';
|
|
7
4
|
import { DisposableCollection } from '@opensumi/ide-core-common';
|
|
8
5
|
|
|
9
|
-
import { NetSocketConnection, WSWebSocketConnection } from './connection';
|
|
10
6
|
import { IConnectionShape } from './connection/types';
|
|
11
|
-
import {
|
|
7
|
+
import { oneOf7 } from './fury-extends/one-of';
|
|
12
8
|
import { createWebSocketConnection } from './message';
|
|
13
|
-
import {
|
|
9
|
+
import { ISumiConnectionOptions, SumiConnection } from './rpc/connection';
|
|
14
10
|
import { ILogger } from './types';
|
|
15
11
|
|
|
16
12
|
/**
|
|
@@ -103,7 +99,6 @@ export class WSChannel {
|
|
|
103
99
|
}>();
|
|
104
100
|
|
|
105
101
|
public id: string;
|
|
106
|
-
public LOG_TAG = '[WSChannel]';
|
|
107
102
|
|
|
108
103
|
public channelPath: string;
|
|
109
104
|
|
|
@@ -129,16 +124,6 @@ export class WSChannel {
|
|
|
129
124
|
return channel;
|
|
130
125
|
}
|
|
131
126
|
|
|
132
|
-
static forWebSocket(socket: WebSocket, options: IWSChannelCreateOptions) {
|
|
133
|
-
const wsConnection = new WSWebSocketConnection(socket);
|
|
134
|
-
return WSChannel.forClient(wsConnection, options);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
static forNetSocket(socket: net.Socket, options: IWSChannelCreateOptions) {
|
|
138
|
-
const wsConnection = new NetSocketConnection(socket);
|
|
139
|
-
return WSChannel.forClient(wsConnection, options);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
127
|
constructor(public connection: IConnectionShape<Uint8Array>, options: IWSChannelCreateOptions) {
|
|
143
128
|
const { id, logger } = options;
|
|
144
129
|
this.id = id;
|
|
@@ -146,8 +131,6 @@ export class WSChannel {
|
|
|
146
131
|
if (logger) {
|
|
147
132
|
this.logger = logger;
|
|
148
133
|
}
|
|
149
|
-
|
|
150
|
-
this.LOG_TAG = `[WSChannel] [id:${id}]`;
|
|
151
134
|
}
|
|
152
135
|
|
|
153
136
|
onMessage(cb: (data: string) => any) {
|
|
@@ -236,9 +219,9 @@ export class WSChannel {
|
|
|
236
219
|
|
|
237
220
|
createConnection() {
|
|
238
221
|
return {
|
|
239
|
-
onceClose: (cb) => this.onceClose(cb),
|
|
240
|
-
onMessage: (cb) => this.onBinary(cb),
|
|
241
|
-
send: (data) => {
|
|
222
|
+
onceClose: (cb: (code: number, reason: string) => void) => this.onceClose(cb),
|
|
223
|
+
onMessage: (cb: (data: Uint8Array) => any) => this.onBinary(cb),
|
|
224
|
+
send: (data: Uint8Array) => {
|
|
242
225
|
this.sendBinary(data);
|
|
243
226
|
},
|
|
244
227
|
dispose() {},
|
|
@@ -291,7 +274,7 @@ export const CloseProtocol = Type.object('close', {
|
|
|
291
274
|
reason: Type.string(),
|
|
292
275
|
});
|
|
293
276
|
|
|
294
|
-
const serializer =
|
|
277
|
+
const serializer = oneOf7([
|
|
295
278
|
PingProtocol,
|
|
296
279
|
PongProtocol,
|
|
297
280
|
OpenProtocol,
|
|
@@ -308,3 +291,18 @@ export function stringify(obj: ChannelMessage): Uint8Array {
|
|
|
308
291
|
export function parse(input: Uint8Array): ChannelMessage {
|
|
309
292
|
return serializer.deserialize(input) as any;
|
|
310
293
|
}
|
|
294
|
+
|
|
295
|
+
const _pingMessage: PingMessage = {
|
|
296
|
+
kind: 'ping',
|
|
297
|
+
id: '',
|
|
298
|
+
clientId: '',
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
const _pongMessage: PongMessage = {
|
|
302
|
+
kind: 'pong',
|
|
303
|
+
id: '',
|
|
304
|
+
clientId: '',
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
export const pingMessage = stringify(_pingMessage);
|
|
308
|
+
export const pongMessage = stringify(_pongMessage);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import net from 'net';
|
|
2
|
+
|
|
3
|
+
import { ILogger } from '../common';
|
|
4
|
+
import { NetSocketConnection } from '../common/connection';
|
|
5
|
+
import { BaseCommonChannelHandler } from '../common/server-handler';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Channel Handler for electron backend
|
|
9
|
+
*/
|
|
10
|
+
export class ElectronChannelHandler extends BaseCommonChannelHandler {
|
|
11
|
+
constructor(private server: net.Server, logger: ILogger = console) {
|
|
12
|
+
super('electron-channel-handler', logger);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
doHeartbeat(connection: any): void {
|
|
16
|
+
// do nothing
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
listen() {
|
|
20
|
+
this.logger.log('init Common Channel Handler');
|
|
21
|
+
this.server.on('connection', (connection: net.Socket) => {
|
|
22
|
+
const netConnection = new NetSocketConnection(connection);
|
|
23
|
+
this.receiveConnection(netConnection);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './channel-handler';
|