@opensumi/ide-connection 3.0.4 → 3.0.5-next-1717466130.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 +10 -1
- package/lib/browser/ws-channel-handler.d.ts.map +1 -1
- package/lib/browser/ws-channel-handler.js +11 -22
- package/lib/browser/ws-channel-handler.js.map +1 -1
- package/lib/common/channel/index.d.ts +2 -0
- package/lib/common/channel/index.d.ts.map +1 -0
- package/lib/common/channel/index.js +5 -0
- package/lib/common/channel/index.js.map +1 -0
- package/lib/common/channel/types.d.ts +66 -0
- package/lib/common/channel/types.d.ts.map +1 -0
- package/lib/common/channel/types.js +8 -0
- package/lib/common/channel/types.js.map +1 -0
- package/lib/common/connection/drivers/simple.d.ts +7 -7
- package/lib/common/connection/drivers/simple.d.ts.map +1 -1
- package/lib/common/connection/drivers/simple.js.map +1 -1
- package/lib/common/index.d.ts +4 -0
- package/lib/common/index.d.ts.map +1 -1
- package/lib/common/index.js +4 -0
- package/lib/common/index.js.map +1 -1
- package/lib/common/rpc/connection.d.ts +5 -4
- package/lib/common/rpc/connection.d.ts.map +1 -1
- package/lib/common/rpc/connection.js +21 -37
- package/lib/common/rpc/connection.js.map +1 -1
- package/lib/common/rpc/message-io.d.ts +62 -11
- package/lib/common/rpc/message-io.d.ts.map +1 -1
- package/lib/common/rpc/message-io.js +111 -10
- package/lib/common/rpc/message-io.js.map +1 -1
- package/lib/common/rpc/multiplexer.d.ts +11 -11
- package/lib/common/rpc/multiplexer.d.ts.map +1 -1
- package/lib/common/rpc/multiplexer.js +18 -17
- package/lib/common/rpc/multiplexer.js.map +1 -1
- package/lib/common/rpc-service/index.d.ts +1 -0
- package/lib/common/rpc-service/index.d.ts.map +1 -1
- package/lib/common/rpc-service/index.js +1 -0
- package/lib/common/rpc-service/index.js.map +1 -1
- package/lib/common/rpc-service/proxy/json.d.ts.map +1 -1
- package/lib/common/rpc-service/proxy/json.js +2 -2
- package/lib/common/rpc-service/proxy/json.js.map +1 -1
- package/lib/common/rpc-service/proxy/sumi.d.ts.map +1 -1
- package/lib/common/rpc-service/proxy/sumi.js +2 -2
- package/lib/common/rpc-service/proxy/sumi.js.map +1 -1
- package/lib/common/rpc-service/registry.d.ts +2 -2
- package/lib/common/rpc-service/registry.d.ts.map +1 -1
- package/lib/common/rpc-service/registry.js +6 -0
- package/lib/common/rpc-service/registry.js.map +1 -1
- package/lib/common/serializer/fury.d.ts +122 -0
- package/lib/common/serializer/fury.d.ts.map +1 -0
- package/lib/common/serializer/fury.js +51 -0
- package/lib/common/serializer/fury.js.map +1 -0
- package/lib/common/serializer/index.d.ts +7 -0
- package/lib/common/serializer/index.d.ts.map +1 -0
- package/lib/common/serializer/index.js +22 -0
- package/lib/common/serializer/index.js.map +1 -0
- package/lib/common/serializer/raw.d.ts +4 -0
- package/lib/common/serializer/raw.d.ts.map +1 -0
- package/lib/common/serializer/raw.js +8 -0
- package/lib/common/serializer/raw.js.map +1 -0
- package/lib/common/serializer/types.d.ts +5 -0
- package/lib/common/serializer/types.d.ts.map +1 -0
- package/lib/common/serializer/types.js +3 -0
- package/lib/common/serializer/types.js.map +1 -0
- package/lib/common/server-handler.d.ts +7 -1
- package/lib/common/server-handler.d.ts.map +1 -1
- package/lib/common/server-handler.js +13 -11
- package/lib/common/server-handler.js.map +1 -1
- package/lib/common/ws-channel.d.ts +10 -202
- package/lib/common/ws-channel.d.ts.map +1 -1
- package/lib/common/ws-channel.js +40 -92
- package/lib/common/ws-channel.js.map +1 -1
- package/package.json +5 -5
- package/src/browser/ws-channel-handler.ts +29 -26
- package/src/common/channel/index.ts +1 -0
- package/src/common/channel/types.ts +82 -0
- package/src/common/connection/drivers/simple.ts +5 -5
- package/src/common/index.ts +4 -0
- package/src/common/rpc/connection.ts +28 -44
- package/src/common/rpc/message-io.ts +172 -10
- package/src/common/rpc/multiplexer.ts +27 -29
- package/src/common/rpc-service/index.ts +1 -0
- package/src/common/rpc-service/proxy/json.ts +13 -11
- package/src/common/rpc-service/proxy/sumi.ts +5 -3
- package/src/common/rpc-service/registry.ts +10 -2
- package/src/common/serializer/fury.ts +61 -0
- package/src/common/serializer/index.ts +24 -0
- package/src/common/serializer/raw.ts +8 -0
- package/src/common/serializer/types.ts +4 -0
- package/src/common/server-handler.ts +24 -26
- package/src/common/ws-channel.ts +63 -225
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export type ChannelMessage =
|
|
2
|
+
| PingMessage
|
|
3
|
+
| PongMessage
|
|
4
|
+
| OpenMessage
|
|
5
|
+
| ServerReadyMessage
|
|
6
|
+
| DataMessage
|
|
7
|
+
| BinaryMessage
|
|
8
|
+
| CloseMessage
|
|
9
|
+
| ErrorMessage;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* `ping` and `pong` are used to detect whether the connection is alive.
|
|
13
|
+
*/
|
|
14
|
+
export interface PingMessage {
|
|
15
|
+
kind: 'ping';
|
|
16
|
+
id: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* when server receive a `ping` message, it should reply a `pong` message, vice versa.
|
|
21
|
+
*/
|
|
22
|
+
export interface PongMessage {
|
|
23
|
+
kind: 'pong';
|
|
24
|
+
id: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* `data` message indicate that the channel has received some data.
|
|
29
|
+
* the `content` field is the data, it should be a string.
|
|
30
|
+
*/
|
|
31
|
+
export interface DataMessage {
|
|
32
|
+
kind: 'data';
|
|
33
|
+
id: string;
|
|
34
|
+
content: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface BinaryMessage {
|
|
38
|
+
kind: 'binary';
|
|
39
|
+
id: string;
|
|
40
|
+
binary: Uint8Array;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface CloseMessage {
|
|
44
|
+
kind: 'close';
|
|
45
|
+
id: string;
|
|
46
|
+
code: number;
|
|
47
|
+
reason: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* `open` message is used to open a new channel.
|
|
52
|
+
* `path` is used to identify which handler should be used to handle the channel.
|
|
53
|
+
* `clientId` is used to identify the client.
|
|
54
|
+
*/
|
|
55
|
+
export interface OpenMessage {
|
|
56
|
+
kind: 'open';
|
|
57
|
+
id: string;
|
|
58
|
+
path: string;
|
|
59
|
+
clientId: string;
|
|
60
|
+
connectionToken: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export enum ErrorMessageCode {
|
|
64
|
+
ChannelNotFound = 1,
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface ErrorMessage {
|
|
68
|
+
kind: 'error';
|
|
69
|
+
id: string;
|
|
70
|
+
code: ErrorMessageCode;
|
|
71
|
+
message: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* when server receive a `open` message, it should reply a `server-ready` message.
|
|
76
|
+
* this is indicate that the channel is ready to use.
|
|
77
|
+
*/
|
|
78
|
+
export interface ServerReadyMessage {
|
|
79
|
+
kind: 'server-ready';
|
|
80
|
+
id: string;
|
|
81
|
+
token: string;
|
|
82
|
+
}
|
|
@@ -2,19 +2,19 @@ import { IDisposable } from '@opensumi/ide-core-common';
|
|
|
2
2
|
|
|
3
3
|
import { BaseConnection } from './base';
|
|
4
4
|
|
|
5
|
-
export class SimpleConnection extends BaseConnection<
|
|
5
|
+
export class SimpleConnection<T = Uint8Array> extends BaseConnection<T> {
|
|
6
6
|
constructor(
|
|
7
7
|
public options: {
|
|
8
|
-
send?: (data:
|
|
9
|
-
onMessage?: (cb: (data:
|
|
8
|
+
send?: (data: T) => void;
|
|
9
|
+
onMessage?: (cb: (data: T) => void) => IDisposable;
|
|
10
10
|
} = {},
|
|
11
11
|
) {
|
|
12
12
|
super();
|
|
13
13
|
}
|
|
14
|
-
send(data:
|
|
14
|
+
send(data: T): void {
|
|
15
15
|
this.options.send?.(data);
|
|
16
16
|
}
|
|
17
|
-
onMessage(cb: (data:
|
|
17
|
+
onMessage(cb: (data: T) => void): IDisposable {
|
|
18
18
|
if (this.options.onMessage) {
|
|
19
19
|
return this.options.onMessage(cb);
|
|
20
20
|
}
|
package/src/common/index.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
export * from './rpc-service/proxy';
|
|
2
|
+
export * from './rpc-service';
|
|
2
3
|
export * from './rpc/multiplexer';
|
|
3
4
|
export * from './rpcProtocol';
|
|
4
5
|
export * from './capturer';
|
|
5
6
|
export * from './ws-channel';
|
|
6
7
|
export * from './connect';
|
|
7
8
|
export * from './types';
|
|
9
|
+
export * from './connection';
|
|
10
|
+
export * from './serializer';
|
|
11
|
+
export * from './channel';
|
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
DisposableStore,
|
|
6
6
|
IDisposable,
|
|
7
7
|
canceled,
|
|
8
|
-
parseError,
|
|
9
8
|
} from '@opensumi/ide-utils';
|
|
10
9
|
import { SumiReadableStream, isReadableStream, listenReadable } from '@opensumi/ide-utils/lib/stream';
|
|
11
10
|
|
|
@@ -15,9 +14,8 @@ import { METHOD_NOT_REGISTERED } from '../constants';
|
|
|
15
14
|
import { ILogger } from '../types';
|
|
16
15
|
|
|
17
16
|
import { MethodTimeoutError } from './errors';
|
|
18
|
-
import { MessageIO, OperationType,
|
|
17
|
+
import { IMessageIO, MessageIO, OperationType, RPCErrorMessage, RPCResponseMessage } from './message-io';
|
|
19
18
|
import {
|
|
20
|
-
IRequestHeaders,
|
|
21
19
|
IResponseHeaders,
|
|
22
20
|
TGenericNotificationHandler,
|
|
23
21
|
TGenericRequestHandler,
|
|
@@ -38,6 +36,8 @@ export interface ISumiConnectionOptions {
|
|
|
38
36
|
* The name of the connection, used for debugging(and can see in opensumi-devtools).
|
|
39
37
|
*/
|
|
40
38
|
name?: string;
|
|
39
|
+
|
|
40
|
+
io?: IMessageIO;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
const chunkedResponseHeaders: IResponseHeaders = {
|
|
@@ -55,13 +55,13 @@ export class SumiConnection implements IDisposable {
|
|
|
55
55
|
private _requestId = 0;
|
|
56
56
|
private _callbacks = new Map<number, TRequestCallback>();
|
|
57
57
|
|
|
58
|
-
private readonly
|
|
58
|
+
private readonly _reqTimeoutHandles = new Map<number, NodeJS.Timeout | number>();
|
|
59
59
|
private readonly _cancellationTokenSources = new Map<number, CancellationTokenSource>();
|
|
60
60
|
private readonly _knownCanceledRequests = new Set<number>();
|
|
61
61
|
|
|
62
62
|
protected activeRequestPool = new Map<number, SumiReadableStream<any>>();
|
|
63
63
|
|
|
64
|
-
public io
|
|
64
|
+
public io: IMessageIO;
|
|
65
65
|
protected logger: ILogger;
|
|
66
66
|
|
|
67
67
|
protected capturer: Capturer;
|
|
@@ -73,6 +73,8 @@ export class SumiConnection implements IDisposable {
|
|
|
73
73
|
this.logger = getDebugLogger();
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
this.io = options.io || new MessageIO();
|
|
77
|
+
|
|
76
78
|
this.capturer = new Capturer(options.name || 'sumi');
|
|
77
79
|
this.disposable.add(this.capturer);
|
|
78
80
|
}
|
|
@@ -113,7 +115,7 @@ export class SumiConnection implements IDisposable {
|
|
|
113
115
|
const timeoutHandle = setTimeout(() => {
|
|
114
116
|
this._handleTimeout(method, requestId);
|
|
115
117
|
}, this.options.timeout);
|
|
116
|
-
this.
|
|
118
|
+
this._reqTimeoutHandles.set(requestId, timeoutHandle);
|
|
117
119
|
}
|
|
118
120
|
|
|
119
121
|
const cancellationToken: CancellationToken | undefined =
|
|
@@ -146,13 +148,13 @@ export class SumiConnection implements IDisposable {
|
|
|
146
148
|
}
|
|
147
149
|
|
|
148
150
|
private _handleTimeout(method: string, requestId: number) {
|
|
149
|
-
if (!this._callbacks.has(requestId) || !this.
|
|
151
|
+
if (!this._callbacks.has(requestId) || !this._reqTimeoutHandles.has(requestId)) {
|
|
150
152
|
return;
|
|
151
153
|
}
|
|
152
154
|
|
|
153
155
|
const callback = this._callbacks.get(requestId)!;
|
|
154
156
|
this._callbacks.delete(requestId);
|
|
155
|
-
this.
|
|
157
|
+
this._reqTimeoutHandles.delete(requestId);
|
|
156
158
|
callback(nullHeaders, new MethodTimeoutError(method));
|
|
157
159
|
}
|
|
158
160
|
|
|
@@ -193,35 +195,29 @@ export class SumiConnection implements IDisposable {
|
|
|
193
195
|
}
|
|
194
196
|
|
|
195
197
|
listen() {
|
|
196
|
-
const { reader } = this.io;
|
|
197
|
-
|
|
198
198
|
this.disposable.add(
|
|
199
199
|
this.socket.onMessage((data) => {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
const opType = reader.uint8() as OperationType;
|
|
205
|
-
const requestId = reader.uint32();
|
|
206
|
-
|
|
207
|
-
if (this._timeoutHandles.has(requestId)) {
|
|
208
|
-
// Ignore some jest test scenarios where clearTimeout is not defined.
|
|
209
|
-
if (typeof clearTimeout === 'function') {
|
|
210
|
-
// @ts-ignore
|
|
211
|
-
clearTimeout(this._timeoutHandles.get(requestId));
|
|
212
|
-
}
|
|
213
|
-
this._timeoutHandles.delete(requestId);
|
|
214
|
-
}
|
|
200
|
+
const message = this.io.parse(data);
|
|
201
|
+
|
|
202
|
+
const opType = message.kind;
|
|
203
|
+
const requestId = message.requestId;
|
|
215
204
|
|
|
216
205
|
switch (opType) {
|
|
206
|
+
case OperationType.Error:
|
|
217
207
|
case OperationType.Response: {
|
|
218
|
-
const method =
|
|
219
|
-
const
|
|
208
|
+
const { headers, method } = message;
|
|
209
|
+
const err = (message as RPCErrorMessage).error;
|
|
210
|
+
const result = (message as RPCResponseMessage).result;
|
|
211
|
+
|
|
212
|
+
if (this._reqTimeoutHandles.has(requestId)) {
|
|
213
|
+
clearTimeout(this._reqTimeoutHandles.get(requestId));
|
|
214
|
+
this._reqTimeoutHandles.delete(requestId);
|
|
215
|
+
}
|
|
220
216
|
|
|
221
217
|
const runCallback = (headers: IResponseHeaders, error?: any, result?: any) => {
|
|
222
218
|
const callback = this._callbacks.get(requestId);
|
|
223
219
|
if (!callback) {
|
|
224
|
-
this.logger.error(`Cannot find callback for request ${requestId}: ${method}
|
|
220
|
+
this.logger.error(`Cannot find callback for request ${requestId}: ${method}`);
|
|
225
221
|
return;
|
|
226
222
|
}
|
|
227
223
|
|
|
@@ -230,17 +226,6 @@ export class SumiConnection implements IDisposable {
|
|
|
230
226
|
callback(headers, error, result);
|
|
231
227
|
};
|
|
232
228
|
|
|
233
|
-
const headers = this.io.responseHeadersSerializer.read();
|
|
234
|
-
let err: any;
|
|
235
|
-
let result: any;
|
|
236
|
-
if (status === Status.Err) {
|
|
237
|
-
// todo: move to processor
|
|
238
|
-
const content = reader.stringOfVarUInt32();
|
|
239
|
-
err = parseError(content);
|
|
240
|
-
} else {
|
|
241
|
-
result = this.io.getProcessor(method).readResponse();
|
|
242
|
-
}
|
|
243
|
-
|
|
244
229
|
if (headers && headers.chunked) {
|
|
245
230
|
let activeReq: SumiReadableStream<any>;
|
|
246
231
|
if (this.activeRequestPool.has(requestId)) {
|
|
@@ -275,9 +260,7 @@ export class SumiConnection implements IDisposable {
|
|
|
275
260
|
case OperationType.Notification:
|
|
276
261
|
// fall through
|
|
277
262
|
case OperationType.Request: {
|
|
278
|
-
const method =
|
|
279
|
-
const headers = this.io.requestHeadersSerializer.read() as IRequestHeaders;
|
|
280
|
-
const args = this.io.getProcessor(method).readRequest();
|
|
263
|
+
const { method, headers, args } = message;
|
|
281
264
|
|
|
282
265
|
if (headers.cancelable) {
|
|
283
266
|
const tokenSource = new CancellationTokenSource();
|
|
@@ -321,16 +304,17 @@ export class SumiConnection implements IDisposable {
|
|
|
321
304
|
},
|
|
322
305
|
onEnd: () => {
|
|
323
306
|
this.socket.send(this.io.Response(requestId, method, chunkedResponseHeaders, null));
|
|
307
|
+
this._cancellationTokenSources.delete(requestId);
|
|
324
308
|
},
|
|
325
309
|
onError: (err) => {
|
|
326
310
|
this.socket.send(this.io.Error(requestId, method, chunkedResponseHeaders, err));
|
|
311
|
+
this._cancellationTokenSources.delete(requestId);
|
|
327
312
|
},
|
|
328
313
|
});
|
|
329
314
|
} else {
|
|
330
315
|
this.socket.send(this.io.Response(requestId, method, nullHeaders, result));
|
|
316
|
+
this._cancellationTokenSources.delete(requestId);
|
|
331
317
|
}
|
|
332
|
-
|
|
333
|
-
this._cancellationTokenSources.delete(requestId);
|
|
334
318
|
};
|
|
335
319
|
|
|
336
320
|
const onError = (err: Error) => {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import Fury, { Serializer, Type, TypeDescription } from '@furyjs/fury';
|
|
2
2
|
import { generateSerializer } from '@furyjs/fury/dist/lib/gen';
|
|
3
|
+
import { PlatformBuffer } from '@furyjs/fury/dist/lib/platformBuffer';
|
|
3
4
|
import { BinaryReader, BinaryWriter } from '@furyjs/fury/dist/lib/type';
|
|
4
5
|
|
|
5
|
-
import { stringifyError } from '@opensumi/ide-core-common/lib/utils';
|
|
6
|
+
import { parseError, stringifyError } from '@opensumi/ide-core-common/lib/utils';
|
|
6
7
|
|
|
7
8
|
import { AnySerializer, IObjectTransfer } from '../fury-extends/any';
|
|
8
9
|
import { furyFactory } from '../fury-extends/shared';
|
|
@@ -24,11 +25,7 @@ export enum OperationType {
|
|
|
24
25
|
Notification,
|
|
25
26
|
Response,
|
|
26
27
|
Cancel,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
export enum Status {
|
|
30
|
-
OK,
|
|
31
|
-
Err,
|
|
28
|
+
Error,
|
|
32
29
|
}
|
|
33
30
|
|
|
34
31
|
export const HeadersProto = {
|
|
@@ -45,6 +42,7 @@ const PacketPrefix = {
|
|
|
45
42
|
Notification: (OperationType.Notification << 8) | ProtoVersionV1,
|
|
46
43
|
Response: (OperationType.Response << 8) | ProtoVersionV1,
|
|
47
44
|
Cancel: (OperationType.Cancel << 8) | ProtoVersionV1,
|
|
45
|
+
Error: (OperationType.Error << 8) | ProtoVersionV1,
|
|
48
46
|
} as const;
|
|
49
47
|
|
|
50
48
|
class SumiProtocolSerializer implements IProtocolSerializer {
|
|
@@ -105,7 +103,66 @@ export class AnyProtocolSerializer implements IProtocolSerializer {
|
|
|
105
103
|
}
|
|
106
104
|
}
|
|
107
105
|
|
|
108
|
-
export
|
|
106
|
+
export interface RPCRequestMessage {
|
|
107
|
+
kind: OperationType.Request;
|
|
108
|
+
requestId: number;
|
|
109
|
+
method: string;
|
|
110
|
+
headers: IRequestHeaders;
|
|
111
|
+
args: any[];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface RPCNotificationMessage {
|
|
115
|
+
kind: OperationType.Notification;
|
|
116
|
+
requestId: number;
|
|
117
|
+
method: string;
|
|
118
|
+
headers: IRequestHeaders;
|
|
119
|
+
args: any[];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export interface RPCResponseMessage {
|
|
123
|
+
kind: OperationType.Response;
|
|
124
|
+
requestId: number;
|
|
125
|
+
method: string;
|
|
126
|
+
headers: IResponseHeaders;
|
|
127
|
+
result: any;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export interface RPCErrorMessage {
|
|
131
|
+
kind: OperationType.Error;
|
|
132
|
+
requestId: number;
|
|
133
|
+
method: string;
|
|
134
|
+
headers: IResponseHeaders;
|
|
135
|
+
error: any;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export interface RPCCancelMessage {
|
|
139
|
+
kind: OperationType.Cancel;
|
|
140
|
+
requestId: number;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export type RPCMessage =
|
|
144
|
+
| RPCRequestMessage
|
|
145
|
+
| RPCNotificationMessage
|
|
146
|
+
| RPCResponseMessage
|
|
147
|
+
| RPCErrorMessage
|
|
148
|
+
| RPCCancelMessage;
|
|
149
|
+
|
|
150
|
+
export abstract class IMessageIO<T = any> {
|
|
151
|
+
abstract loadProtocolMethod?(
|
|
152
|
+
methodProtocol: TSumiProtocolMethod,
|
|
153
|
+
options?: { nameConverter?: (str: string) => string },
|
|
154
|
+
): void;
|
|
155
|
+
|
|
156
|
+
abstract Request(requestId: number, method: string, headers: IRequestHeaders, args: any[]): T;
|
|
157
|
+
abstract Notification(requestId: number, method: string, headers: IRequestHeaders, args: any[]): T;
|
|
158
|
+
abstract Cancel(requestId: number): T;
|
|
159
|
+
abstract Response(requestId: number, method: string, headers: Record<string, any>, result: any): T;
|
|
160
|
+
abstract Error(requestId: number, method: string, headers: Record<string, any>, error: any): T;
|
|
161
|
+
|
|
162
|
+
abstract parse(data: T): RPCMessage;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export class MessageIO extends IMessageIO<PlatformBuffer> {
|
|
109
166
|
fury: Fury;
|
|
110
167
|
reader: BinaryReader;
|
|
111
168
|
writer: BinaryWriter;
|
|
@@ -118,6 +175,7 @@ export class MessageIO {
|
|
|
118
175
|
responseHeadersSerializer: Serializer<IResponseHeaders, IRequestHeaders>;
|
|
119
176
|
|
|
120
177
|
constructor() {
|
|
178
|
+
super();
|
|
121
179
|
const fury = furyFactory();
|
|
122
180
|
this.fury = fury.fury;
|
|
123
181
|
this.reader = fury.reader;
|
|
@@ -216,7 +274,6 @@ export class MessageIO {
|
|
|
216
274
|
writer.uint16(PacketPrefix.Response);
|
|
217
275
|
writer.uint32(requestId);
|
|
218
276
|
writer.stringOfVarUInt32(method);
|
|
219
|
-
writer.uint16(Status.OK);
|
|
220
277
|
this.responseHeadersSerializer.write(headers);
|
|
221
278
|
this.getProcessor(method).writeResponse(result);
|
|
222
279
|
|
|
@@ -227,13 +284,118 @@ export class MessageIO {
|
|
|
227
284
|
const { writer } = this;
|
|
228
285
|
writer.reset();
|
|
229
286
|
|
|
230
|
-
writer.uint16(PacketPrefix.
|
|
287
|
+
writer.uint16(PacketPrefix.Error);
|
|
231
288
|
writer.uint32(requestId);
|
|
232
289
|
writer.stringOfVarUInt32(method);
|
|
233
|
-
writer.uint16(Status.Err);
|
|
234
290
|
this.responseHeadersSerializer.write(headers);
|
|
235
291
|
writer.stringOfVarUInt32(stringifyError(error));
|
|
236
292
|
|
|
237
293
|
return writer.dump();
|
|
238
294
|
}
|
|
295
|
+
|
|
296
|
+
parse(data: PlatformBuffer): RPCMessage {
|
|
297
|
+
const { reader } = this;
|
|
298
|
+
reader.reset(data);
|
|
299
|
+
|
|
300
|
+
// skip version, currently only have version 1
|
|
301
|
+
reader.skip(1);
|
|
302
|
+
const opType = reader.uint8() as OperationType;
|
|
303
|
+
const requestId = reader.uint32();
|
|
304
|
+
|
|
305
|
+
switch (opType) {
|
|
306
|
+
case OperationType.Request:
|
|
307
|
+
case OperationType.Notification: {
|
|
308
|
+
const method = reader.stringOfVarUInt32();
|
|
309
|
+
const headers = this.requestHeadersSerializer.read() as IRequestHeaders;
|
|
310
|
+
const args = this.getProcessor(method).readRequest();
|
|
311
|
+
return {
|
|
312
|
+
kind: opType,
|
|
313
|
+
requestId,
|
|
314
|
+
method,
|
|
315
|
+
headers,
|
|
316
|
+
args,
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
case OperationType.Error: {
|
|
320
|
+
const method = reader.stringOfVarUInt32();
|
|
321
|
+
const headers = this.responseHeadersSerializer.read() as IResponseHeaders;
|
|
322
|
+
const error = parseError(reader.stringOfVarUInt32());
|
|
323
|
+
return {
|
|
324
|
+
kind: OperationType.Error,
|
|
325
|
+
requestId,
|
|
326
|
+
method,
|
|
327
|
+
headers,
|
|
328
|
+
error,
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
case OperationType.Response: {
|
|
332
|
+
const method = reader.stringOfVarUInt32();
|
|
333
|
+
const headers = this.responseHeadersSerializer.read() as IResponseHeaders;
|
|
334
|
+
const result = this.getProcessor(method).readResponse();
|
|
335
|
+
return {
|
|
336
|
+
kind: OperationType.Response,
|
|
337
|
+
requestId,
|
|
338
|
+
method,
|
|
339
|
+
headers,
|
|
340
|
+
result,
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
case OperationType.Cancel:
|
|
344
|
+
return {
|
|
345
|
+
kind: OperationType.Cancel,
|
|
346
|
+
requestId,
|
|
347
|
+
};
|
|
348
|
+
default:
|
|
349
|
+
throw new Error(`Unknown message type: ${opType}`);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
export class RawMessageIO implements IMessageIO<RPCMessage> {
|
|
355
|
+
Request(requestId: number, method: string, headers: IRequestHeaders, args: any[]): RPCRequestMessage {
|
|
356
|
+
return {
|
|
357
|
+
kind: OperationType.Request,
|
|
358
|
+
requestId,
|
|
359
|
+
method,
|
|
360
|
+
headers,
|
|
361
|
+
args,
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
Notification(requestId: number, method: string, headers: IRequestHeaders, args: any[]): RPCNotificationMessage {
|
|
365
|
+
return {
|
|
366
|
+
kind: OperationType.Notification,
|
|
367
|
+
requestId,
|
|
368
|
+
method,
|
|
369
|
+
headers,
|
|
370
|
+
args,
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
Cancel(requestId: number): RPCCancelMessage {
|
|
374
|
+
return {
|
|
375
|
+
kind: OperationType.Cancel,
|
|
376
|
+
requestId,
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
Response(requestId: number, method: string, headers: Record<string, any>, result: any): RPCResponseMessage {
|
|
380
|
+
return {
|
|
381
|
+
kind: OperationType.Response,
|
|
382
|
+
requestId,
|
|
383
|
+
headers,
|
|
384
|
+
method,
|
|
385
|
+
result,
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
Error(requestId: number, method: string, headers: Record<string, any>, error: any): RPCErrorMessage {
|
|
389
|
+
return {
|
|
390
|
+
kind: OperationType.Error,
|
|
391
|
+
requestId,
|
|
392
|
+
method,
|
|
393
|
+
headers,
|
|
394
|
+
error,
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
parse(data: any): RPCMessage {
|
|
399
|
+
return data;
|
|
400
|
+
}
|
|
239
401
|
}
|
|
@@ -2,7 +2,7 @@ import { BaseConnection } from '../connection';
|
|
|
2
2
|
import { ExtObjectTransfer } from '../fury-extends/any';
|
|
3
3
|
|
|
4
4
|
import { ISumiConnectionOptions, SumiConnection } from './connection';
|
|
5
|
-
import { AnyProtocolSerializer } from './message-io';
|
|
5
|
+
import { AnyProtocolSerializer, MessageIO } from './message-io';
|
|
6
6
|
import { TSumiProtocol } from './types';
|
|
7
7
|
|
|
8
8
|
export class ProxyIdentifier<T = any> {
|
|
@@ -20,13 +20,6 @@ export class ProxyIdentifier<T = any> {
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
export interface ISumiMultiplexerConnectionOptions extends ISumiConnectionOptions {
|
|
24
|
-
/**
|
|
25
|
-
* Known protocols that will be loaded automatically when a proxy is created.
|
|
26
|
-
*/
|
|
27
|
-
knownProtocols?: Record<string, TSumiProtocol>;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
23
|
export const IRPCProtocol = Symbol('IRPCProtocol');
|
|
31
24
|
export interface IRPCProtocol {
|
|
32
25
|
getProxy<T>(proxyId: ProxyIdentifier<T>): T;
|
|
@@ -34,6 +27,24 @@ export interface IRPCProtocol {
|
|
|
34
27
|
get<T>(identifier: ProxyIdentifier<T>): T;
|
|
35
28
|
}
|
|
36
29
|
|
|
30
|
+
/**
|
|
31
|
+
*
|
|
32
|
+
* @param protocols Known protocols that will be loaded automatically when a proxy is created.
|
|
33
|
+
* @returns
|
|
34
|
+
*/
|
|
35
|
+
export function createExtMessageIO(protocols?: Map<ProxyIdentifier<any>, TSumiProtocol>) {
|
|
36
|
+
const io = new MessageIO();
|
|
37
|
+
io.setAnySerializer(new AnyProtocolSerializer(io.writer, io.reader, ExtObjectTransfer));
|
|
38
|
+
|
|
39
|
+
protocols?.forEach((protocol, proxyId) => {
|
|
40
|
+
io.loadProtocol(protocol, {
|
|
41
|
+
nameConverter: (str: string) => SumiConnectionMultiplexer.getRPCName(proxyId.serviceId, str),
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
return io;
|
|
46
|
+
}
|
|
47
|
+
|
|
37
48
|
/**
|
|
38
49
|
* A connection multiplexer that allows to register multiple local RPC services and to create proxies for them.
|
|
39
50
|
*/
|
|
@@ -41,7 +52,7 @@ export class SumiConnectionMultiplexer extends SumiConnection implements IRPCPro
|
|
|
41
52
|
protected static SEP = '/';
|
|
42
53
|
protected static SEP_LENGTH = SumiConnectionMultiplexer.SEP.length;
|
|
43
54
|
|
|
44
|
-
|
|
55
|
+
static getRPCName(serviceId: string, methodName: string) {
|
|
45
56
|
return `${serviceId}${SumiConnectionMultiplexer.SEP}${methodName}`;
|
|
46
57
|
}
|
|
47
58
|
|
|
@@ -56,14 +67,16 @@ export class SumiConnectionMultiplexer extends SumiConnection implements IRPCPro
|
|
|
56
67
|
|
|
57
68
|
protected readonly _locals: Map<string, any>;
|
|
58
69
|
protected readonly _proxies: Map<string, any>;
|
|
59
|
-
protected _knownProtocols: Record<string, TSumiProtocol>;
|
|
60
70
|
|
|
61
|
-
|
|
62
|
-
|
|
71
|
+
io: MessageIO;
|
|
72
|
+
|
|
73
|
+
constructor(protected socket: BaseConnection<Uint8Array>, protected options: ISumiConnectionOptions = {}) {
|
|
74
|
+
super(socket, {
|
|
75
|
+
...options,
|
|
76
|
+
io: options.io || createExtMessageIO(),
|
|
77
|
+
});
|
|
63
78
|
this._locals = new Map();
|
|
64
79
|
this._proxies = new Map();
|
|
65
|
-
this._knownProtocols = options.knownProtocols || {};
|
|
66
|
-
this.io.setAnySerializer(new AnyProtocolSerializer(this.io.writer, this.io.reader, ExtObjectTransfer));
|
|
67
80
|
|
|
68
81
|
this.onRequestNotFound((rpcName: string, args: any[]) => this.invoke(rpcName, args));
|
|
69
82
|
|
|
@@ -75,10 +88,6 @@ export class SumiConnectionMultiplexer extends SumiConnection implements IRPCPro
|
|
|
75
88
|
public set<T>(identifier: ProxyIdentifier<T>, instance: any) {
|
|
76
89
|
const id = SumiConnectionMultiplexer.normalizeServiceId(identifier.serviceId);
|
|
77
90
|
this._locals.set(id, instance);
|
|
78
|
-
const protocol = this._knownProtocols[identifier.serviceId];
|
|
79
|
-
if (protocol) {
|
|
80
|
-
this.loadProtocol(id, protocol);
|
|
81
|
-
}
|
|
82
91
|
|
|
83
92
|
return instance;
|
|
84
93
|
}
|
|
@@ -87,21 +96,10 @@ export class SumiConnectionMultiplexer extends SumiConnection implements IRPCPro
|
|
|
87
96
|
return this._locals.get(SumiConnectionMultiplexer.normalizeServiceId(identifier.serviceId));
|
|
88
97
|
}
|
|
89
98
|
|
|
90
|
-
protected loadProtocol(rpcId: string, protocol: TSumiProtocol) {
|
|
91
|
-
this.io.loadProtocol(protocol, {
|
|
92
|
-
nameConverter: (str: string) => SumiConnectionMultiplexer.getRPCName(rpcId, str),
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
|
|
96
99
|
public getProxy<T>(proxyId: ProxyIdentifier<T>) {
|
|
97
100
|
const serviceId = SumiConnectionMultiplexer.normalizeServiceId(proxyId.serviceId);
|
|
98
101
|
|
|
99
102
|
if (!this._proxies.has(serviceId)) {
|
|
100
|
-
const protocol = this._knownProtocols[proxyId.serviceId];
|
|
101
|
-
if (protocol) {
|
|
102
|
-
this.loadProtocol(serviceId, protocol);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
103
|
this._proxies.set(serviceId, this._createProxy(serviceId));
|
|
106
104
|
}
|
|
107
105
|
|
|
@@ -127,16 +127,18 @@ export class ProxyJson extends ProxyBase<MessageConnection> {
|
|
|
127
127
|
listen(connection: MessageConnection): void {
|
|
128
128
|
super.listen(connection);
|
|
129
129
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
130
|
+
this._disposables.add(
|
|
131
|
+
connection.onRequest((method) => {
|
|
132
|
+
if (!this.registry.has(method)) {
|
|
133
|
+
const requestId = this.nextRequestId();
|
|
134
|
+
this.capturer.captureOnRequest(requestId, method, []);
|
|
135
|
+
const result = {
|
|
136
|
+
data: METHOD_NOT_REGISTERED,
|
|
137
|
+
};
|
|
138
|
+
this.capturer.captureOnRequestFail(requestId, method, result.data);
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
}),
|
|
142
|
+
);
|
|
141
143
|
}
|
|
142
144
|
}
|
|
@@ -35,8 +35,10 @@ export class ProxySumi extends ProxyBase<SumiConnection> {
|
|
|
35
35
|
|
|
36
36
|
listen(connection: SumiConnection): void {
|
|
37
37
|
super.listen(connection);
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
this._disposables.add(
|
|
39
|
+
connection.onRequestNotFound(() => {
|
|
40
|
+
throw METHOD_NOT_REGISTERED;
|
|
41
|
+
}),
|
|
42
|
+
);
|
|
41
43
|
}
|
|
42
44
|
}
|