@opensumi/ide-connection 2.27.3-next-1706520813.0 → 2.27.3-rc-1706687185.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/lib/browser/ws-channel-handler.d.ts +9 -7
- package/lib/browser/ws-channel-handler.d.ts.map +1 -1
- package/lib/browser/ws-channel-handler.js +65 -64
- package/lib/browser/ws-channel-handler.js.map +1 -1
- package/lib/common/connect.d.ts +6 -57
- package/lib/common/connect.d.ts.map +1 -1
- package/lib/common/connect.js +9 -168
- package/lib/common/connect.js.map +1 -1
- package/lib/common/connection/buffers.d.ts +55 -0
- package/lib/common/connection/buffers.d.ts.map +1 -0
- package/lib/common/connection/buffers.js +244 -0
- package/lib/common/connection/buffers.js.map +1 -0
- package/lib/common/connection/drivers/base.d.ts +9 -0
- package/lib/common/connection/drivers/base.d.ts.map +1 -0
- package/lib/common/connection/drivers/base.js +11 -0
- package/lib/common/connection/drivers/base.js.map +1 -0
- package/lib/common/connection/drivers/empty.d.ts +8 -0
- package/lib/common/connection/drivers/empty.d.ts.map +1 -0
- package/lib/common/connection/drivers/empty.js +21 -0
- package/lib/common/connection/drivers/empty.js.map +1 -0
- package/lib/common/connection/drivers/index.d.ts +6 -0
- package/lib/common/connection/drivers/index.d.ts.map +1 -0
- package/lib/common/connection/drivers/index.js +9 -0
- package/lib/common/connection/drivers/index.js.map +1 -0
- package/lib/common/connection/drivers/node-message-port.d.ts +12 -0
- package/lib/common/connection/drivers/node-message-port.d.ts.map +1 -0
- package/lib/common/connection/drivers/node-message-port.js +31 -0
- package/lib/common/connection/drivers/node-message-port.js.map +1 -0
- package/lib/common/connection/drivers/reconnecting-websocket.d.ts +15 -0
- package/lib/common/connection/drivers/reconnecting-websocket.d.ts.map +1 -0
- package/lib/common/connection/drivers/reconnecting-websocket.js +83 -0
- package/lib/common/connection/drivers/reconnecting-websocket.js.map +1 -0
- package/lib/common/connection/drivers/socket.d.ts +17 -0
- package/lib/common/connection/drivers/socket.d.ts.map +1 -0
- package/lib/common/connection/drivers/socket.js +56 -0
- package/lib/common/connection/drivers/socket.js.map +1 -0
- package/lib/common/connection/drivers/stream-decoder.d.ts +67 -0
- package/lib/common/connection/drivers/stream-decoder.d.ts.map +1 -0
- package/lib/common/connection/drivers/stream-decoder.js +171 -0
- package/lib/common/connection/drivers/stream-decoder.js.map +1 -0
- package/lib/common/connection/drivers/utils.d.ts +12 -0
- package/lib/common/connection/drivers/utils.d.ts.map +1 -0
- package/lib/common/connection/drivers/utils.js +49 -0
- package/lib/common/connection/drivers/utils.js.map +1 -0
- package/lib/common/connection/drivers/ws-websocket.d.ts +11 -0
- package/lib/common/connection/drivers/ws-websocket.d.ts.map +1 -0
- package/lib/common/connection/drivers/ws-websocket.js +31 -0
- package/lib/common/connection/drivers/ws-websocket.js.map +1 -0
- package/lib/common/connection/index.d.ts +2 -0
- package/lib/common/connection/index.d.ts.map +1 -0
- package/lib/common/connection/index.js +5 -0
- package/lib/common/connection/index.js.map +1 -0
- package/lib/common/connection/types.d.ts +7 -0
- package/lib/common/connection/types.d.ts.map +1 -0
- package/lib/common/connection/types.js +3 -0
- package/lib/common/connection/types.js.map +1 -0
- package/lib/common/constants.d.ts +2 -0
- package/lib/common/constants.d.ts.map +1 -0
- package/lib/common/constants.js +5 -0
- package/lib/common/constants.js.map +1 -0
- package/lib/common/{rpcProtocol.d.ts → ext-rpc-protocol.d.ts} +10 -11
- package/lib/common/ext-rpc-protocol.d.ts.map +1 -0
- package/lib/common/{rpcProtocol.js → ext-rpc-protocol.js} +22 -19
- package/lib/common/ext-rpc-protocol.js.map +1 -0
- package/lib/common/index.d.ts +2 -1
- package/lib/common/index.d.ts.map +1 -1
- package/lib/common/index.js +2 -1
- package/lib/common/index.js.map +1 -1
- package/lib/common/proxy/base.d.ts +22 -0
- package/lib/common/proxy/base.d.ts.map +1 -0
- package/lib/common/proxy/base.js +47 -0
- package/lib/common/proxy/base.js.map +1 -0
- package/lib/common/proxy/index.d.ts +8 -0
- package/lib/common/proxy/index.d.ts.map +1 -0
- package/lib/common/proxy/index.js +12 -0
- package/lib/common/proxy/index.js.map +1 -0
- package/lib/common/proxy/legacy.d.ts +23 -0
- package/lib/common/proxy/legacy.d.ts.map +1 -0
- package/lib/common/proxy/legacy.js +183 -0
- package/lib/common/proxy/legacy.js.map +1 -0
- package/lib/common/rpc-service/center.d.ts +20 -0
- package/lib/common/rpc-service/center.d.ts.map +1 -0
- package/lib/common/rpc-service/center.js +100 -0
- package/lib/common/rpc-service/center.js.map +1 -0
- package/lib/common/rpc-service/index.d.ts +3 -0
- package/lib/common/rpc-service/index.d.ts.map +1 -0
- package/lib/common/rpc-service/index.js +6 -0
- package/lib/common/rpc-service/index.js.map +1 -0
- package/lib/common/rpc-service/stub.d.ts +15 -0
- package/lib/common/rpc-service/stub.d.ts.map +1 -0
- package/lib/common/rpc-service/stub.js +48 -0
- package/lib/common/rpc-service/stub.js.map +1 -0
- package/lib/common/types.d.ts +15 -0
- package/lib/common/types.d.ts.map +1 -0
- package/lib/common/types.js +9 -0
- package/lib/common/types.js.map +1 -0
- package/lib/common/utils.d.ts +4 -2
- package/lib/common/utils.d.ts.map +1 -1
- package/lib/common/utils.js +32 -9
- package/lib/common/utils.js.map +1 -1
- package/lib/common/ws-channel.d.ts +104 -27
- package/lib/common/ws-channel.d.ts.map +1 -1
- package/lib/common/ws-channel.js +96 -27
- package/lib/common/ws-channel.js.map +1 -1
- package/lib/node/common-channel-handler.d.ts +18 -16
- package/lib/node/common-channel-handler.d.ts.map +1 -1
- package/lib/node/common-channel-handler.js +42 -59
- package/lib/node/common-channel-handler.js.map +1 -1
- package/lib/node/index.d.ts +0 -3
- package/lib/node/index.d.ts.map +1 -1
- package/lib/node/index.js +0 -5
- package/lib/node/index.js.map +1 -1
- package/lib/node/ws.d.ts +1 -1
- package/lib/node/ws.d.ts.map +1 -1
- package/lib/node/ws.js +2 -0
- package/lib/node/ws.js.map +1 -1
- package/package.json +9 -7
- package/src/browser/ws-channel-handler.ts +82 -70
- package/src/common/connect.ts +7 -193
- package/src/common/connection/buffers.ts +284 -0
- package/src/common/connection/drivers/base.ts +15 -0
- package/src/common/connection/drivers/empty.ts +19 -0
- package/src/common/connection/drivers/index.ts +5 -0
- package/src/common/connection/drivers/node-message-port.ts +33 -0
- package/src/common/connection/drivers/reconnecting-websocket.ts +86 -0
- package/src/common/connection/drivers/socket.ts +62 -0
- package/src/common/connection/drivers/stream-decoder.ts +196 -0
- package/src/common/connection/drivers/utils.ts +52 -0
- package/src/common/connection/drivers/ws-websocket.ts +31 -0
- package/src/common/connection/index.ts +1 -0
- package/src/common/connection/types.ts +7 -0
- package/src/common/constants.ts +1 -0
- package/src/common/{rpcProtocol.ts → ext-rpc-protocol.ts} +43 -31
- package/src/common/index.ts +2 -1
- package/src/common/proxy/base.ts +67 -0
- package/src/common/proxy/index.ts +10 -0
- package/src/common/proxy/legacy.ts +200 -0
- package/src/common/rpc-service/center.ts +124 -0
- package/src/common/rpc-service/index.ts +2 -0
- package/src/common/rpc-service/stub.ts +49 -0
- package/src/common/types.ts +17 -0
- package/src/common/utils.ts +31 -8
- package/src/common/ws-channel.ts +175 -48
- package/src/node/common-channel-handler.ts +68 -80
- package/src/node/index.ts +0 -5
- package/src/node/ws.ts +3 -1
- package/lib/common/proxy.d.ts +0 -47
- package/lib/common/proxy.d.ts.map +0 -1
- package/lib/common/proxy.js +0 -272
- package/lib/common/proxy.js.map +0 -1
- package/lib/common/rpcProtocol.d.ts.map +0 -1
- package/lib/common/rpcProtocol.js.map +0 -1
- package/lib/node/connect.d.ts +0 -4
- package/lib/node/connect.d.ts.map +0 -1
- package/lib/node/connect.js +0 -9
- package/lib/node/connect.js.map +0 -1
- package/src/common/proxy.ts +0 -303
- package/src/node/connect.ts +0 -11
package/src/common/ws-channel.ts
CHANGED
|
@@ -1,105 +1,188 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type net from 'net';
|
|
2
|
+
|
|
3
|
+
import Fury, { Type } from '@furyjs/fury';
|
|
4
|
+
import type WebSocket from 'ws';
|
|
5
|
+
|
|
6
|
+
import { EventEmitter } from '@opensumi/events';
|
|
7
|
+
import { DisposableCollection } from '@opensumi/ide-core-common';
|
|
8
|
+
|
|
9
|
+
import { NetSocketConnection, WSWebSocketConnection } from './connection';
|
|
10
|
+
import { IConnectionShape } from './connection/types';
|
|
11
|
+
import { createWebSocketConnection } from './message';
|
|
12
|
+
import { ILogger } from './types';
|
|
2
13
|
|
|
3
14
|
export interface IWebSocket {
|
|
4
15
|
send(content: string): void;
|
|
5
|
-
close(...args): void;
|
|
16
|
+
close(...args: any[]): void;
|
|
6
17
|
onMessage(cb: (data: any) => void): void;
|
|
7
18
|
onError(cb: (reason: any) => void): void;
|
|
8
19
|
onClose(cb: (code: number, reason: string) => void): void;
|
|
9
20
|
}
|
|
10
21
|
|
|
11
|
-
|
|
12
|
-
|
|
22
|
+
/**
|
|
23
|
+
* `ping` and `pong` are used to detect whether the connection is alive.
|
|
24
|
+
*/
|
|
25
|
+
export interface PingMessage {
|
|
26
|
+
kind: 'ping';
|
|
27
|
+
id: string;
|
|
13
28
|
clientId: string;
|
|
14
29
|
}
|
|
15
|
-
|
|
16
|
-
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* when server receive a `ping` message, it should reply a `pong` message, vice versa.
|
|
33
|
+
*/
|
|
34
|
+
export interface PongMessage {
|
|
35
|
+
kind: 'pong';
|
|
36
|
+
id: string;
|
|
17
37
|
clientId: string;
|
|
18
38
|
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* `open` message is used to open a new channel.
|
|
42
|
+
* `path` is used to identify which handler should be used to handle the channel.
|
|
43
|
+
* `clientId` is used to identify the client.
|
|
44
|
+
*/
|
|
19
45
|
export interface OpenMessage {
|
|
20
46
|
kind: 'open';
|
|
21
|
-
id:
|
|
47
|
+
id: string;
|
|
22
48
|
path: string;
|
|
49
|
+
clientId: string;
|
|
23
50
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* when server receive a `open` message, it should reply a `server-ready` message.
|
|
54
|
+
* this is indicate that the channel is ready to use.
|
|
55
|
+
*/
|
|
56
|
+
export interface ServerReadyMessage {
|
|
57
|
+
kind: 'server-ready';
|
|
58
|
+
id: string;
|
|
27
59
|
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* `data` message indicate that the channel has received some data.
|
|
63
|
+
* the `content` field is the data, it should be a string.
|
|
64
|
+
*/
|
|
28
65
|
export interface DataMessage {
|
|
29
66
|
kind: 'data';
|
|
30
|
-
id:
|
|
67
|
+
id: string;
|
|
31
68
|
content: string;
|
|
32
69
|
}
|
|
70
|
+
|
|
33
71
|
export interface CloseMessage {
|
|
34
72
|
kind: 'close';
|
|
35
|
-
id:
|
|
73
|
+
id: string;
|
|
36
74
|
code: number;
|
|
37
75
|
reason: string;
|
|
38
76
|
}
|
|
39
|
-
|
|
77
|
+
|
|
78
|
+
export type ChannelMessage = PingMessage | PongMessage | OpenMessage | ServerReadyMessage | DataMessage | CloseMessage;
|
|
79
|
+
|
|
80
|
+
export interface IWSChannelCreateOptions {
|
|
81
|
+
/**
|
|
82
|
+
* every channel's unique id, it only used in client to server architecture.
|
|
83
|
+
* server will store this id and use it to identify which channel should be used.
|
|
84
|
+
*/
|
|
85
|
+
id: string;
|
|
86
|
+
logger?: ILogger;
|
|
87
|
+
}
|
|
40
88
|
|
|
41
89
|
export class WSChannel implements IWebSocket {
|
|
42
|
-
|
|
90
|
+
protected emitter = new EventEmitter<{
|
|
91
|
+
message: [data: string];
|
|
92
|
+
open: [id: string];
|
|
93
|
+
reopen: [];
|
|
94
|
+
close: [code?: number, reason?: string];
|
|
95
|
+
}>();
|
|
96
|
+
|
|
97
|
+
public id: string;
|
|
98
|
+
public LOG_TAG = '[WSChannel]';
|
|
99
|
+
|
|
43
100
|
public channelPath: string;
|
|
44
101
|
|
|
45
|
-
|
|
46
|
-
private fireMessage: (data: any) => void;
|
|
47
|
-
private fireOpen: (id: number) => void;
|
|
48
|
-
public fireReOpen: () => void;
|
|
49
|
-
private fireClose: (code: number, reason: string) => void;
|
|
102
|
+
logger: ILogger = console;
|
|
50
103
|
|
|
51
|
-
|
|
104
|
+
static forClient(connection: IConnectionShape<Uint8Array>, options: IWSChannelCreateOptions) {
|
|
105
|
+
const disposable = new DisposableCollection();
|
|
106
|
+
const channel = new WSChannel(connection, options);
|
|
52
107
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
108
|
+
disposable.push(
|
|
109
|
+
connection.onMessage((data) => {
|
|
110
|
+
channel.handleMessage(parse(data));
|
|
111
|
+
}),
|
|
112
|
+
);
|
|
113
|
+
disposable.push(channel);
|
|
114
|
+
|
|
115
|
+
disposable.push(
|
|
116
|
+
connection.onceClose(() => {
|
|
117
|
+
disposable.dispose();
|
|
118
|
+
}),
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
return channel;
|
|
58
122
|
}
|
|
59
123
|
|
|
60
|
-
|
|
61
|
-
|
|
124
|
+
static forWebSocket(socket: WebSocket, options: IWSChannelCreateOptions) {
|
|
125
|
+
const wsConnection = new WSWebSocketConnection(socket);
|
|
126
|
+
return WSChannel.forClient(wsConnection, options);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
static forNetSocket(socket: net.Socket, options: IWSChannelCreateOptions) {
|
|
130
|
+
const wsConnection = new NetSocketConnection(socket);
|
|
131
|
+
return WSChannel.forClient(wsConnection, options);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
constructor(public connection: IConnectionShape<Uint8Array>, options: IWSChannelCreateOptions) {
|
|
135
|
+
const { id, logger } = options;
|
|
136
|
+
this.id = id;
|
|
137
|
+
|
|
138
|
+
if (logger) {
|
|
139
|
+
this.logger = logger;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
this.LOG_TAG = `[WSChannel] [id:${id}]`;
|
|
62
143
|
}
|
|
63
144
|
|
|
64
145
|
// server
|
|
65
|
-
onMessage(cb: (data:
|
|
66
|
-
this.
|
|
146
|
+
onMessage(cb: (data: string) => any) {
|
|
147
|
+
return this.emitter.on('message', cb);
|
|
67
148
|
}
|
|
68
|
-
onOpen(cb: (id:
|
|
69
|
-
this.
|
|
149
|
+
onOpen(cb: (id: string) => void) {
|
|
150
|
+
return this.emitter.on('open', cb);
|
|
70
151
|
}
|
|
71
|
-
|
|
72
|
-
this.
|
|
152
|
+
onReopen(cb: () => void) {
|
|
153
|
+
return this.emitter.on('reopen', cb);
|
|
73
154
|
}
|
|
74
|
-
|
|
75
|
-
this.
|
|
155
|
+
serverReady() {
|
|
156
|
+
this.connection.send(
|
|
76
157
|
stringify({
|
|
77
|
-
kind: 'ready',
|
|
158
|
+
kind: 'server-ready',
|
|
78
159
|
id: this.id,
|
|
79
160
|
}),
|
|
80
161
|
);
|
|
81
162
|
}
|
|
163
|
+
|
|
82
164
|
handleMessage(msg: ChannelMessage) {
|
|
83
|
-
if (msg.kind === 'ready'
|
|
84
|
-
this.
|
|
85
|
-
} else if (msg.kind === 'data'
|
|
86
|
-
this.
|
|
165
|
+
if (msg.kind === 'server-ready') {
|
|
166
|
+
this.emitter.emit('open', msg.id);
|
|
167
|
+
} else if (msg.kind === 'data') {
|
|
168
|
+
this.emitter.emit('message', msg.content);
|
|
87
169
|
}
|
|
88
170
|
}
|
|
89
171
|
|
|
90
172
|
// client
|
|
91
|
-
open(path: string) {
|
|
173
|
+
open(path: string, clientId: string) {
|
|
92
174
|
this.channelPath = path;
|
|
93
|
-
this.
|
|
175
|
+
this.connection.send(
|
|
94
176
|
stringify({
|
|
95
177
|
kind: 'open',
|
|
96
178
|
id: this.id,
|
|
97
179
|
path,
|
|
180
|
+
clientId,
|
|
98
181
|
}),
|
|
99
182
|
);
|
|
100
183
|
}
|
|
101
184
|
send(content: string) {
|
|
102
|
-
this.
|
|
185
|
+
this.connection.send(
|
|
103
186
|
stringify({
|
|
104
187
|
kind: 'data',
|
|
105
188
|
id: this.id,
|
|
@@ -107,14 +190,36 @@ export class WSChannel implements IWebSocket {
|
|
|
107
190
|
}),
|
|
108
191
|
);
|
|
109
192
|
}
|
|
193
|
+
hasMessageListener() {
|
|
194
|
+
return this.emitter.hasListener('message');
|
|
195
|
+
}
|
|
110
196
|
onError() {}
|
|
111
|
-
close(code
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
197
|
+
close(code?: number, reason?: string) {
|
|
198
|
+
this.emitter.emit('close', code, reason);
|
|
199
|
+
}
|
|
200
|
+
fireReopen() {
|
|
201
|
+
this.emitter.emit('reopen');
|
|
115
202
|
}
|
|
116
203
|
onClose(cb: (code: number, reason: string) => void) {
|
|
117
|
-
this.
|
|
204
|
+
return this.emitter.on('close', cb);
|
|
205
|
+
}
|
|
206
|
+
createMessageConnection() {
|
|
207
|
+
return createWebSocketConnection(this);
|
|
208
|
+
}
|
|
209
|
+
dispose() {
|
|
210
|
+
this.emitter.dispose();
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
listen(channel: WSChannel) {
|
|
214
|
+
channel.onMessage((data) => {
|
|
215
|
+
this.send(data);
|
|
216
|
+
});
|
|
217
|
+
channel.onClose((code, reason) => {
|
|
218
|
+
this.close(code, reason);
|
|
219
|
+
});
|
|
220
|
+
channel.onReopen(() => {
|
|
221
|
+
this.fireReopen();
|
|
222
|
+
});
|
|
118
223
|
}
|
|
119
224
|
}
|
|
120
225
|
|
|
@@ -142,3 +247,25 @@ export class ChildConnectPath {
|
|
|
142
247
|
};
|
|
143
248
|
}
|
|
144
249
|
}
|
|
250
|
+
|
|
251
|
+
const fury = new Fury({});
|
|
252
|
+
|
|
253
|
+
export const wsChannelProtocol = Type.object('ws-channel-protocol', {
|
|
254
|
+
kind: Type.string(),
|
|
255
|
+
clientId: Type.string(),
|
|
256
|
+
id: Type.string(),
|
|
257
|
+
path: Type.string(),
|
|
258
|
+
content: Type.string(),
|
|
259
|
+
code: Type.uint32(),
|
|
260
|
+
reason: Type.string(),
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
const wsChannelProtocolSerializer = fury.registerSerializer(wsChannelProtocol);
|
|
264
|
+
|
|
265
|
+
export function stringify(obj: ChannelMessage): Uint8Array {
|
|
266
|
+
return wsChannelProtocolSerializer.serialize(obj);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export function parse(input: Uint8Array): ChannelMessage {
|
|
270
|
+
return wsChannelProtocolSerializer.deserialize(input) as any;
|
|
271
|
+
}
|
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import { MatchFunction, match } from 'path-to-regexp';
|
|
2
|
+
import WebSocket from 'ws';
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { ILogger } from '../common';
|
|
5
|
+
import { WSWebSocketConnection } from '../common/connection';
|
|
6
|
+
import { WSChannel, ChannelMessage, stringify, parse } from '../common/ws-channel';
|
|
6
7
|
|
|
7
8
|
import { WebSocketHandler, CommonChannelHandlerOptions } from './ws';
|
|
8
9
|
|
|
9
|
-
export interface
|
|
10
|
+
export interface IPathHandler {
|
|
10
11
|
dispose: (connection: any, connectionId: string) => void;
|
|
11
|
-
handler: (connection: any, connectionId: string, params?:
|
|
12
|
+
handler: (connection: any, connectionId: string, params?: Record<string, string>) => void;
|
|
12
13
|
reconnect?: (connection: any, connectionId: string) => void;
|
|
13
14
|
connection?: any;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
export class CommonChannelPathHandler {
|
|
17
|
-
private handlerMap: Map<string,
|
|
18
|
+
private handlerMap: Map<string, IPathHandler[]> = new Map();
|
|
18
19
|
private paramsKey: Map<string, string> = new Map();
|
|
19
20
|
|
|
20
|
-
register(channelPath: string, handler:
|
|
21
|
+
register(channelPath: string, handler: IPathHandler) {
|
|
21
22
|
const paramsIndex = channelPath.indexOf('/:');
|
|
22
23
|
const hasParams = paramsIndex >= 0;
|
|
23
24
|
let channelToken = channelPath;
|
|
@@ -28,18 +29,18 @@ export class CommonChannelPathHandler {
|
|
|
28
29
|
if (!this.handlerMap.has(channelToken)) {
|
|
29
30
|
this.handlerMap.set(channelToken, []);
|
|
30
31
|
}
|
|
31
|
-
const handlerArr = this.handlerMap.get(channelToken) as
|
|
32
|
+
const handlerArr = this.handlerMap.get(channelToken) as IPathHandler[];
|
|
32
33
|
const handlerFn = handler.handler.bind(handler);
|
|
33
|
-
const setHandler = (
|
|
34
|
-
handler.connection =
|
|
35
|
-
handlerFn(
|
|
34
|
+
const setHandler = (channel: WSChannel, clientId: string, params: any) => {
|
|
35
|
+
handler.connection = channel;
|
|
36
|
+
handlerFn(channel, clientId, params);
|
|
36
37
|
};
|
|
37
38
|
handler.handler = setHandler;
|
|
38
39
|
handlerArr.push(handler);
|
|
39
40
|
this.handlerMap.set(channelToken, handlerArr);
|
|
40
41
|
}
|
|
41
|
-
getParams(channelPath: string, value: string) {
|
|
42
|
-
const params = {}
|
|
42
|
+
getParams(channelPath: string, value: string): Record<string, string> {
|
|
43
|
+
const params = {} as Record<string, string>;
|
|
43
44
|
if (this.paramsKey.has(channelPath)) {
|
|
44
45
|
const key = this.paramsKey.get(channelPath);
|
|
45
46
|
if (key) {
|
|
@@ -48,7 +49,7 @@ export class CommonChannelPathHandler {
|
|
|
48
49
|
}
|
|
49
50
|
return params;
|
|
50
51
|
}
|
|
51
|
-
removeHandler(channelPath: string, handler:
|
|
52
|
+
removeHandler(channelPath: string, handler: IPathHandler) {
|
|
52
53
|
const paramsIndex = channelPath.indexOf(':');
|
|
53
54
|
const hasParams = paramsIndex >= 0;
|
|
54
55
|
let channelToken = channelPath;
|
|
@@ -65,9 +66,9 @@ export class CommonChannelPathHandler {
|
|
|
65
66
|
get(channelPath: string) {
|
|
66
67
|
return this.handlerMap.get(channelPath);
|
|
67
68
|
}
|
|
68
|
-
disposeConnectionClientId(connection:
|
|
69
|
-
this.handlerMap.forEach((handlerArr:
|
|
70
|
-
handlerArr.forEach((handler:
|
|
69
|
+
disposeConnectionClientId(connection: WebSocket, clientId: string) {
|
|
70
|
+
this.handlerMap.forEach((handlerArr: IPathHandler[]) => {
|
|
71
|
+
handlerArr.forEach((handler: IPathHandler) => {
|
|
71
72
|
handler.dispose(connection, clientId);
|
|
72
73
|
});
|
|
73
74
|
});
|
|
@@ -79,28 +80,26 @@ export class CommonChannelPathHandler {
|
|
|
79
80
|
|
|
80
81
|
export const commonChannelPathHandler = new CommonChannelPathHandler();
|
|
81
82
|
|
|
82
|
-
|
|
83
|
+
/**
|
|
84
|
+
* Channel Handler for nodejs
|
|
85
|
+
*/
|
|
83
86
|
export class CommonChannelHandler extends WebSocketHandler {
|
|
84
|
-
static channelId = 0;
|
|
85
|
-
|
|
86
87
|
public handlerId = 'common-channel';
|
|
87
|
-
private wsServer:
|
|
88
|
-
protected handlerRoute:
|
|
89
|
-
private channelMap: Map<string
|
|
90
|
-
private connectionMap: Map<string, ws> = new Map();
|
|
88
|
+
private wsServer: WebSocket.Server;
|
|
89
|
+
protected handlerRoute: MatchFunction;
|
|
90
|
+
private channelMap: Map<string, WSChannel> = new Map();
|
|
91
91
|
private heartbeatMap: Map<string, NodeJS.Timeout> = new Map();
|
|
92
92
|
|
|
93
|
-
constructor(routePath: string, private logger:
|
|
93
|
+
constructor(routePath: string, private logger: ILogger = console, private options: CommonChannelHandlerOptions = {}) {
|
|
94
94
|
super();
|
|
95
|
-
|
|
96
|
-
this.handlerRoute = route(`${routePath}`);
|
|
95
|
+
this.handlerRoute = match(routePath, options.pathMatchOptions);
|
|
97
96
|
this.initWSServer();
|
|
98
97
|
}
|
|
99
|
-
|
|
98
|
+
|
|
99
|
+
private heartbeat(connectionId: string, connection: WebSocket) {
|
|
100
100
|
const timer = global.setTimeout(() => {
|
|
101
101
|
connection.ping();
|
|
102
|
-
|
|
103
|
-
this.hearbeat(connectionId, connection);
|
|
102
|
+
this.heartbeat(connectionId, connection);
|
|
104
103
|
}, 5000);
|
|
105
104
|
|
|
106
105
|
this.heartbeatMap.set(connectionId, timer);
|
|
@@ -108,40 +107,38 @@ export class CommonChannelHandler extends WebSocketHandler {
|
|
|
108
107
|
|
|
109
108
|
private initWSServer() {
|
|
110
109
|
this.logger.log('init Common Channel Handler');
|
|
111
|
-
this.wsServer = new
|
|
110
|
+
this.wsServer = new WebSocket.Server({
|
|
112
111
|
noServer: true,
|
|
113
112
|
...this.options.wsServerOptions,
|
|
114
113
|
});
|
|
115
|
-
this.wsServer.on('connection', (connection:
|
|
116
|
-
let
|
|
117
|
-
|
|
114
|
+
this.wsServer.on('connection', (connection: WebSocket) => {
|
|
115
|
+
let clientId: string;
|
|
116
|
+
|
|
117
|
+
connection.on('message', (msg: Uint8Array) => {
|
|
118
118
|
let msgObj: ChannelMessage;
|
|
119
119
|
try {
|
|
120
120
|
msgObj = parse(msg);
|
|
121
121
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
this.hearbeat(connectionId, connection);
|
|
131
|
-
// channel 消息处理
|
|
122
|
+
if (msgObj.kind === 'ping') {
|
|
123
|
+
connection.send(
|
|
124
|
+
stringify({
|
|
125
|
+
kind: 'pong',
|
|
126
|
+
id: msgObj.id,
|
|
127
|
+
clientId,
|
|
128
|
+
}),
|
|
129
|
+
);
|
|
132
130
|
} else if (msgObj.kind === 'open') {
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
this.logger.log(`
|
|
131
|
+
const { id, path } = msgObj;
|
|
132
|
+
clientId = msgObj.clientId;
|
|
133
|
+
this.logger.log(`open a new connection channel ${clientId} with path ${path}`);
|
|
134
|
+
this.heartbeat(id, connection);
|
|
136
135
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const channel = new WSChannel(connectionSend, channelId);
|
|
140
|
-
this.channelMap.set(channelId, channel);
|
|
136
|
+
const channel = new WSChannel(new WSWebSocketConnection(connection), { id });
|
|
137
|
+
this.channelMap.set(id, channel);
|
|
141
138
|
|
|
142
139
|
// 根据 path 拿到注册的 handler
|
|
143
140
|
let handlerArr = commonChannelPathHandler.get(path);
|
|
144
|
-
let params;
|
|
141
|
+
let params: Record<string, string> | undefined;
|
|
145
142
|
// 尝试通过父路径查找处理函数,如server/:id方式注册的handler
|
|
146
143
|
if (!handlerArr) {
|
|
147
144
|
const slashIndex = path.indexOf('/');
|
|
@@ -155,11 +152,11 @@ export class CommonChannelHandler extends WebSocketHandler {
|
|
|
155
152
|
if (handlerArr) {
|
|
156
153
|
for (let i = 0, len = handlerArr.length; i < len; i++) {
|
|
157
154
|
const handler = handlerArr[i];
|
|
158
|
-
handler.handler(channel,
|
|
155
|
+
handler.handler(channel, clientId, params);
|
|
159
156
|
}
|
|
160
157
|
}
|
|
161
158
|
|
|
162
|
-
channel.
|
|
159
|
+
channel.serverReady();
|
|
163
160
|
} else {
|
|
164
161
|
const { id } = msgObj;
|
|
165
162
|
const channel = this.channelMap.get(id);
|
|
@@ -170,51 +167,42 @@ export class CommonChannelHandler extends WebSocketHandler {
|
|
|
170
167
|
}
|
|
171
168
|
}
|
|
172
169
|
} catch (e) {
|
|
173
|
-
this.logger.
|
|
170
|
+
this.logger.error('handle connection message error', e);
|
|
174
171
|
}
|
|
175
172
|
});
|
|
176
173
|
|
|
177
|
-
connection.
|
|
178
|
-
commonChannelPathHandler.disposeConnectionClientId(connection,
|
|
174
|
+
connection.once('close', () => {
|
|
175
|
+
commonChannelPathHandler.disposeConnectionClientId(connection, clientId);
|
|
179
176
|
|
|
180
|
-
if (this.heartbeatMap.has(
|
|
181
|
-
clearTimeout(this.heartbeatMap.get(
|
|
182
|
-
this.heartbeatMap.delete(
|
|
177
|
+
if (this.heartbeatMap.has(clientId)) {
|
|
178
|
+
clearTimeout(this.heartbeatMap.get(clientId) as NodeJS.Timeout);
|
|
179
|
+
this.heartbeatMap.delete(clientId);
|
|
183
180
|
|
|
184
|
-
this.logger.
|
|
181
|
+
this.logger.log(`Clear heartbeat from channel ${clientId}`);
|
|
185
182
|
}
|
|
186
183
|
|
|
187
184
|
Array.from(this.channelMap.values())
|
|
188
|
-
.filter((channel) => channel.id.toString().indexOf(
|
|
185
|
+
.filter((channel) => channel.id.toString().indexOf(clientId) !== -1)
|
|
189
186
|
.forEach((channel) => {
|
|
190
187
|
channel.close(1, 'close');
|
|
188
|
+
channel.dispose();
|
|
191
189
|
this.channelMap.delete(channel.id);
|
|
192
|
-
this.logger.
|
|
190
|
+
this.logger.log(`Remove connection channel ${channel.id}`);
|
|
193
191
|
});
|
|
194
192
|
});
|
|
195
193
|
});
|
|
196
194
|
}
|
|
197
195
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
connection.send(content, (err: any) => {
|
|
201
|
-
if (err) {
|
|
202
|
-
this.logger.log(err);
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
};
|
|
207
|
-
public handleUpgrade(wsPathname: string, request: any, socket: any, head: any): boolean {
|
|
208
|
-
const routeResult = this.handlerRoute(wsPathname);
|
|
196
|
+
public handleUpgrade(pathname: string, request: any, socket: any, head: any): boolean {
|
|
197
|
+
const routeResult = this.handlerRoute(pathname);
|
|
209
198
|
|
|
210
199
|
if (routeResult) {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
pathname: wsPathname,
|
|
200
|
+
this.wsServer.handleUpgrade(request, socket, head, (connection) => {
|
|
201
|
+
(connection as any).routeParam = {
|
|
202
|
+
pathname,
|
|
215
203
|
};
|
|
216
204
|
|
|
217
|
-
wsServer.emit('connection', connection);
|
|
205
|
+
this.wsServer.emit('connection', connection);
|
|
218
206
|
});
|
|
219
207
|
return true;
|
|
220
208
|
}
|
package/src/node/index.ts
CHANGED
package/src/node/ws.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import assert from 'assert';
|
|
1
2
|
import http from 'http';
|
|
2
3
|
import url from 'url';
|
|
3
4
|
|
|
@@ -5,7 +6,7 @@ import ws from 'ws';
|
|
|
5
6
|
|
|
6
7
|
export abstract class WebSocketHandler {
|
|
7
8
|
abstract handlerId: string;
|
|
8
|
-
abstract handleUpgrade(
|
|
9
|
+
abstract handleUpgrade(pathname: string, request: any, socket: any, head: any): boolean;
|
|
9
10
|
init?(): void;
|
|
10
11
|
}
|
|
11
12
|
|
|
@@ -88,6 +89,7 @@ export class WebSocketServerRoute {
|
|
|
88
89
|
const wsServerHandlerArr = this.wsServerHandlerArr;
|
|
89
90
|
|
|
90
91
|
server.on('upgrade', (request, socket, head) => {
|
|
92
|
+
assert(request.url, 'cannot parse url from http request');
|
|
91
93
|
const wsPathname: string = url.parse(request.url).pathname as string;
|
|
92
94
|
|
|
93
95
|
let wsHandlerIndex = 0;
|
package/lib/common/proxy.d.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import type { MessageConnection } from '@opensumi/vscode-jsonrpc/lib/common/connection';
|
|
2
|
-
export interface ILogger {
|
|
3
|
-
warn(...args: any[]): void;
|
|
4
|
-
}
|
|
5
|
-
export declare abstract class RPCService<T = any> {
|
|
6
|
-
rpcClient?: T[];
|
|
7
|
-
rpcRegistered?: boolean;
|
|
8
|
-
register?(): () => Promise<T>;
|
|
9
|
-
get client(): T | undefined;
|
|
10
|
-
}
|
|
11
|
-
export declare const NOTREGISTERMETHOD = "$$NOTREGISTERMETHOD";
|
|
12
|
-
export declare class ProxyClient {
|
|
13
|
-
proxy: any;
|
|
14
|
-
reservedWords: string[];
|
|
15
|
-
constructor(proxy: any, reservedWords?: string[]);
|
|
16
|
-
getClient(): {};
|
|
17
|
-
}
|
|
18
|
-
export declare class RPCProxy {
|
|
19
|
-
target?: RPCService<any> | undefined;
|
|
20
|
-
private connectionPromise;
|
|
21
|
-
private connectionPromiseResolve;
|
|
22
|
-
private connection;
|
|
23
|
-
private proxyService;
|
|
24
|
-
private logger;
|
|
25
|
-
private capture;
|
|
26
|
-
constructor(target?: RPCService<any> | undefined, logger?: ILogger);
|
|
27
|
-
listenService(service: any): void;
|
|
28
|
-
listen(connection: MessageConnection): void;
|
|
29
|
-
createProxy(): any;
|
|
30
|
-
get(target: any, p: PropertyKey): (...args: any[]) => Promise<unknown>;
|
|
31
|
-
private getServiceMethod;
|
|
32
|
-
private bindOnRequest;
|
|
33
|
-
private waitForConnection;
|
|
34
|
-
/**
|
|
35
|
-
* 对于纯数组参数的情况,收到请求/通知后做展开操作
|
|
36
|
-
* 因为在通信层会为每个 rpc 调用添加一个 CancellationToken 参数
|
|
37
|
-
* 如果参数本身是数组, 在方法中如果使用 spread 运算符获取参数(...args),则会出现 [...args, MutableToken] 这种情况
|
|
38
|
-
* 所以发送请求时将这类参数统一再用数组包了一层,形如 [[...args]], 参考 {@link RPCProxy.get get} 方法
|
|
39
|
-
* 此时接收到的数组类参数固定长度为 2,且最后一项一定是 MutableToken
|
|
40
|
-
* @param args
|
|
41
|
-
* @returns args
|
|
42
|
-
*/
|
|
43
|
-
private serializeArguments;
|
|
44
|
-
private onRequest;
|
|
45
|
-
private onNotification;
|
|
46
|
-
}
|
|
47
|
-
//# sourceMappingURL=proxy.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/common/proxy.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gDAAgD,CAAC;AAIxF,MAAM,WAAW,OAAO;IACtB,IAAI,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;CAC5B;AAED,8BAAsB,UAAU,CAAC,CAAC,GAAG,GAAG;IACtC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC;IAChB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC;IAC7B,IAAI,MAAM,kBAET;CACF;AAED,eAAO,MAAM,iBAAiB,wBAAwB,CAAC;AAEvD,qBAAa,WAAW;IACf,KAAK,EAAE,GAAG,CAAC;IACX,aAAa,EAAE,MAAM,EAAE,CAAC;gBAEnB,KAAK,EAAE,GAAG,EAAE,aAAa,WAAW;IAIzC,SAAS;CAcjB;AAMD,qBAAa,QAAQ;IAcA,MAAM,CAAC;IAb1B,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,wBAAwB,CAA0C;IAC1E,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,YAAY,CAAW;IAC/B,OAAO,CAAC,MAAM,CAAU;IAExB,OAAO,CAAC,OAAO;gBAOI,MAAM,CAAC,6BAAY,EAAE,MAAM,CAAC,EAAE,OAAO;IAIjD,aAAa,CAAC,OAAO,KAAA;IAerB,MAAM,CAAC,UAAU,EAAE,iBAAiB;IAUpC,WAAW,IAAI,GAAG;IAMlB,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,WAAW,aAGnB,GAAG,EAAE;IAmExB,OAAO,CAAC,gBAAgB;IAmBxB,OAAO,CAAC,aAAa;IAkErB,OAAO,CAAC,iBAAiB;IAMzB;;;;;;;;OAQG;IACH,OAAO,CAAC,kBAAkB;YASZ,SAAS;IAmBvB,OAAO,CAAC,cAAc;CAOvB"}
|