@opensumi/ide-connection 3.0.4-next-1716529130.0 → 3.0.4-next-1716962745.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.
Files changed (80) hide show
  1. package/lib/browser/ws-channel-handler.d.ts +8 -1
  2. package/lib/browser/ws-channel-handler.d.ts.map +1 -1
  3. package/lib/browser/ws-channel-handler.js +10 -21
  4. package/lib/browser/ws-channel-handler.js.map +1 -1
  5. package/lib/common/channel/index.d.ts +2 -0
  6. package/lib/common/channel/index.d.ts.map +1 -0
  7. package/lib/common/channel/index.js +5 -0
  8. package/lib/common/channel/index.js.map +1 -0
  9. package/lib/common/channel/types.d.ts +66 -0
  10. package/lib/common/channel/types.d.ts.map +1 -0
  11. package/lib/common/channel/types.js +8 -0
  12. package/lib/common/channel/types.js.map +1 -0
  13. package/lib/common/connection/drivers/simple.d.ts +7 -7
  14. package/lib/common/connection/drivers/simple.d.ts.map +1 -1
  15. package/lib/common/connection/drivers/simple.js.map +1 -1
  16. package/lib/common/index.d.ts +4 -0
  17. package/lib/common/index.d.ts.map +1 -1
  18. package/lib/common/index.js +4 -0
  19. package/lib/common/index.js.map +1 -1
  20. package/lib/common/rpc/connection.d.ts +4 -3
  21. package/lib/common/rpc/connection.d.ts.map +1 -1
  22. package/lib/common/rpc/connection.js +14 -30
  23. package/lib/common/rpc/connection.js.map +1 -1
  24. package/lib/common/rpc/message-io.d.ts +54 -11
  25. package/lib/common/rpc/message-io.d.ts.map +1 -1
  26. package/lib/common/rpc/message-io.js +63 -10
  27. package/lib/common/rpc/message-io.js.map +1 -1
  28. package/lib/common/rpc/multiplexer.d.ts +2 -0
  29. package/lib/common/rpc/multiplexer.d.ts.map +1 -1
  30. package/lib/common/rpc/multiplexer.js +1 -0
  31. package/lib/common/rpc/multiplexer.js.map +1 -1
  32. package/lib/common/rpc-service/index.d.ts +1 -0
  33. package/lib/common/rpc-service/index.d.ts.map +1 -1
  34. package/lib/common/rpc-service/index.js +1 -0
  35. package/lib/common/rpc-service/index.js.map +1 -1
  36. package/lib/common/rpc-service/registry.d.ts +2 -2
  37. package/lib/common/rpc-service/registry.d.ts.map +1 -1
  38. package/lib/common/rpc-service/registry.js +6 -0
  39. package/lib/common/rpc-service/registry.js.map +1 -1
  40. package/lib/common/serializer/fury.d.ts +122 -0
  41. package/lib/common/serializer/fury.d.ts.map +1 -0
  42. package/lib/common/serializer/fury.js +51 -0
  43. package/lib/common/serializer/fury.js.map +1 -0
  44. package/lib/common/serializer/index.d.ts +6 -0
  45. package/lib/common/serializer/index.d.ts.map +1 -0
  46. package/lib/common/serializer/index.js +21 -0
  47. package/lib/common/serializer/index.js.map +1 -0
  48. package/lib/common/serializer/raw.d.ts +4 -0
  49. package/lib/common/serializer/raw.d.ts.map +1 -0
  50. package/lib/common/serializer/raw.js +8 -0
  51. package/lib/common/serializer/raw.js.map +1 -0
  52. package/lib/common/serializer/types.d.ts +5 -0
  53. package/lib/common/serializer/types.d.ts.map +1 -0
  54. package/lib/common/serializer/types.js +3 -0
  55. package/lib/common/serializer/types.js.map +1 -0
  56. package/lib/common/server-handler.d.ts +7 -1
  57. package/lib/common/server-handler.d.ts.map +1 -1
  58. package/lib/common/server-handler.js +13 -11
  59. package/lib/common/server-handler.js.map +1 -1
  60. package/lib/common/ws-channel.d.ts +11 -201
  61. package/lib/common/ws-channel.d.ts.map +1 -1
  62. package/lib/common/ws-channel.js +49 -85
  63. package/lib/common/ws-channel.js.map +1 -1
  64. package/package.json +5 -5
  65. package/src/browser/ws-channel-handler.ts +26 -23
  66. package/src/common/channel/index.ts +1 -0
  67. package/src/common/channel/types.ts +82 -0
  68. package/src/common/connection/drivers/simple.ts +5 -5
  69. package/src/common/index.ts +4 -0
  70. package/src/common/rpc/connection.ts +19 -36
  71. package/src/common/rpc/message-io.ts +123 -10
  72. package/src/common/rpc/multiplexer.ts +3 -1
  73. package/src/common/rpc-service/index.ts +1 -0
  74. package/src/common/rpc-service/registry.ts +10 -2
  75. package/src/common/serializer/fury.ts +61 -0
  76. package/src/common/serializer/index.ts +23 -0
  77. package/src/common/serializer/raw.ts +8 -0
  78. package/src/common/serializer/types.ts +4 -0
  79. package/src/common/server-handler.ts +24 -26
  80. package/src/common/ws-channel.ts +72 -207
@@ -0,0 +1,8 @@
1
+ import { ChannelMessage } from '../channel';
2
+
3
+ import { ISerializer } from './types';
4
+
5
+ export const rawSerializer: ISerializer<ChannelMessage, ChannelMessage> = {
6
+ serialize: (message) => message,
7
+ deserialize: (message) => message,
8
+ };
@@ -0,0 +1,4 @@
1
+ export interface ISerializer<FROM, TO> {
2
+ serialize(data: FROM): TO;
3
+ deserialize(data: TO): FROM;
4
+ }
@@ -1,14 +1,9 @@
1
+ import { ChannelMessage, ErrorMessageCode } from './channel/types';
1
2
  import { IConnectionShape } from './connection/types';
3
+ import { furySerializer, wrapSerializer } from './serializer';
4
+ import { ISerializer } from './serializer/types';
2
5
  import { ILogger } from './types';
3
- import {
4
- ChannelMessage,
5
- ErrorMessageCode,
6
- WSChannel,
7
- WSServerChannel,
8
- parse,
9
- pongMessage,
10
- stringify,
11
- } from './ws-channel';
6
+ import { WSChannel, WSServerChannel } from './ws-channel';
12
7
 
13
8
  export interface IPathHandler {
14
9
  dispose: (channel: WSChannel, connectionId: string) => void;
@@ -105,12 +100,21 @@ export class CommonChannelPathHandler {
105
100
 
106
101
  export const commonChannelPathHandler = new CommonChannelPathHandler();
107
102
 
103
+ export interface ChannelHandlerOptions {
104
+ serializer?: ISerializer<ChannelMessage, any>;
105
+ }
106
+
108
107
  export abstract class BaseCommonChannelHandler {
109
108
  protected channelMap: Map<string, WSServerChannel> = new Map();
110
109
 
111
110
  protected heartbeatTimer: NodeJS.Timeout | null = null;
112
111
 
113
- constructor(public handlerId: string, protected logger: ILogger = console) {}
112
+ serializer: ISerializer<ChannelMessage, any> = furySerializer;
113
+ constructor(public handlerId: string, protected logger: ILogger = console, options: ChannelHandlerOptions = {}) {
114
+ if (options.serializer) {
115
+ this.serializer = options.serializer;
116
+ }
117
+ }
114
118
 
115
119
  abstract doHeartbeat(connection: any): void;
116
120
 
@@ -129,24 +133,20 @@ export abstract class BaseCommonChannelHandler {
129
133
  let clientId: string;
130
134
  this.heartbeat(connection);
131
135
 
136
+ const wrappedConnection = wrapSerializer(connection, this.serializer);
137
+
132
138
  const getOrCreateChannel = (id: string, clientId: string) => {
133
139
  let channel = this.channelMap.get(id);
134
140
  if (!channel) {
135
- channel = new WSServerChannel(connection, { id, clientId, logger: this.logger });
141
+ channel = new WSServerChannel(wrappedConnection, { id, clientId, logger: this.logger });
136
142
  this.channelMap.set(id, channel);
137
143
  }
138
144
  return channel;
139
145
  };
140
146
 
141
- connection.onMessage((data: Uint8Array) => {
142
- let msg: ChannelMessage;
147
+ wrappedConnection.onMessage((msg: ChannelMessage) => {
143
148
  try {
144
- msg = parse(data);
145
-
146
149
  switch (msg.kind) {
147
- case 'ping':
148
- connection.send(pongMessage);
149
- break;
150
150
  case 'open': {
151
151
  const { id, path, connectionToken } = msg;
152
152
  clientId = msg.clientId;
@@ -163,14 +163,12 @@ export abstract class BaseCommonChannelHandler {
163
163
  if (channel) {
164
164
  channel.dispatch(msg);
165
165
  } else {
166
- connection.send(
167
- stringify({
168
- kind: 'error',
169
- id,
170
- code: ErrorMessageCode.ChannelNotFound,
171
- message: `channel ${id} not found`,
172
- }),
173
- );
166
+ wrappedConnection.send({
167
+ kind: 'error',
168
+ id,
169
+ code: ErrorMessageCode.ChannelNotFound,
170
+ message: `channel ${id} not found`,
171
+ });
174
172
 
175
173
  this.logger.warn(`channel ${id} is not found`);
176
174
  }
@@ -1,5 +1,3 @@
1
- import { Type } from '@furyjs/fury';
2
-
3
1
  import { EventEmitter } from '@opensumi/events';
4
2
  import {
5
3
  DisposableCollection,
@@ -9,52 +7,12 @@ import {
9
7
  randomString,
10
8
  } from '@opensumi/ide-core-common';
11
9
 
10
+ import { ChannelMessage, ErrorMessageCode } from './channel/types';
12
11
  import { IConnectionShape } from './connection/types';
13
- import { oneOf } from './fury-extends/one-of';
14
12
  import { ISumiConnectionOptions, SumiConnection } from './rpc/connection';
13
+ import { furySerializer, wrapSerializer } from './serializer';
15
14
  import { ILogger } from './types';
16
15
 
17
- /**
18
- * `ping` and `pong` are used to detect whether the connection is alive.
19
- */
20
- export interface PingMessage {
21
- kind: 'ping';
22
- id: string;
23
- clientId: string;
24
- }
25
-
26
- /**
27
- * when server receive a `ping` message, it should reply a `pong` message, vice versa.
28
- */
29
- export interface PongMessage {
30
- kind: 'pong';
31
- id: string;
32
- clientId: string;
33
- }
34
-
35
- /**
36
- * `data` message indicate that the channel has received some data.
37
- * the `content` field is the data, it should be a string.
38
- */
39
- export interface DataMessage {
40
- kind: 'data';
41
- id: string;
42
- content: string;
43
- }
44
-
45
- export interface BinaryMessage {
46
- kind: 'binary';
47
- id: string;
48
- binary: Uint8Array;
49
- }
50
-
51
- export interface CloseMessage {
52
- kind: 'close';
53
- id: string;
54
- code: number;
55
- reason: string;
56
- }
57
-
58
16
  export interface IWSChannelCreateOptions {
59
17
  /**
60
18
  * every channel's unique id, it only used in client to server architecture.
@@ -80,25 +38,25 @@ export class WSChannel {
80
38
 
81
39
  protected onBinaryQueue = this._disposables.add(new EventQueue<Uint8Array>());
82
40
 
83
- protected sendQueue: Uint8Array[] = [];
41
+ protected sendQueue: ChannelMessage[] = [];
84
42
  protected _isServerReady = false;
85
43
  protected _ensureServerReady: boolean | undefined;
86
44
 
87
45
  public id: string;
88
46
 
89
47
  public channelPath: string;
48
+ public clientId: string;
49
+
50
+ protected LOG_TAG = '[WSChannel]';
90
51
 
91
52
  logger: ILogger = console;
92
53
 
93
54
  static forClient(connection: IConnectionShape<Uint8Array>, options: IWSChannelCreateOptions) {
94
55
  const disposable = new DisposableCollection();
95
- const channel = new WSChannel(connection, options);
96
56
 
97
- disposable.push(
98
- connection.onMessage((data) => {
99
- channel.dispatch(parse(data));
100
- }),
101
- );
57
+ const wrappedConnection = wrapSerializer(connection, furySerializer);
58
+ const channel = new WSChannel(wrappedConnection, options);
59
+ disposable.push(channel.listen());
102
60
 
103
61
  connection.onceClose(() => {
104
62
  disposable.dispose();
@@ -107,10 +65,10 @@ export class WSChannel {
107
65
  return channel;
108
66
  }
109
67
 
110
- constructor(public connection: IConnectionShape<Uint8Array>, options: IWSChannelCreateOptions) {
68
+ constructor(public connection: IConnectionShape<ChannelMessage>, options: IWSChannelCreateOptions) {
111
69
  const { id, logger, ensureServerReady } = options;
112
70
  this.id = id;
113
-
71
+ this.LOG_TAG = `[WSChannel id=${this.id}]`;
114
72
  if (logger) {
115
73
  this.logger = logger;
116
74
  }
@@ -120,7 +78,7 @@ export class WSChannel {
120
78
  this._disposables.add(this.emitter.on('binary', (data) => this.onBinaryQueue.push(data)));
121
79
  }
122
80
 
123
- protected inqueue(data: Uint8Array) {
81
+ protected inqueue(data: ChannelMessage) {
124
82
  if (this._ensureServerReady && !this._isServerReady) {
125
83
  if (!this.sendQueue) {
126
84
  this.sendQueue = [];
@@ -182,6 +140,20 @@ export class WSChannel {
182
140
  case 'binary':
183
141
  this.emitter.emit('binary', msg.binary);
184
142
  break;
143
+ case 'error':
144
+ this.logger.error(this.LOG_TAG, `receive error: id: ${msg.id}, code: ${msg.code}, error: ${msg.message}`);
145
+ switch (msg.code) {
146
+ case ErrorMessageCode.ChannelNotFound:
147
+ // 有 channelPath 说明该 channel 曾经被打开过
148
+ // 重新打开 channel
149
+ if (this.channelPath) {
150
+ // 暂停消息发送, 直到收到 server-ready
151
+ this.pause();
152
+ this.open(this.channelPath, this.clientId);
153
+ }
154
+ break;
155
+ }
156
+ break;
185
157
  }
186
158
  }
187
159
 
@@ -192,6 +164,9 @@ export class WSChannel {
192
164
  */
193
165
  open(path: string, clientId: string, connectionToken = randomString(16)) {
194
166
  this.channelPath = path;
167
+ this.clientId = clientId;
168
+
169
+ this.LOG_TAG = `[WSChannel id=${this.id} path=${path}]`;
195
170
 
196
171
  if (this.stateTracer.has(connectionToken)) {
197
172
  this.logger.warn(
@@ -202,15 +177,13 @@ export class WSChannel {
202
177
 
203
178
  this.stateTracer.record(connectionToken);
204
179
 
205
- this.connection.send(
206
- stringify({
207
- kind: 'open',
208
- id: this.id,
209
- path,
210
- clientId,
211
- connectionToken,
212
- }),
213
- );
180
+ this.connection.send({
181
+ kind: 'open',
182
+ id: this.id,
183
+ path,
184
+ clientId,
185
+ connectionToken,
186
+ });
214
187
 
215
188
  if (this._ensureServerReady) {
216
189
  this.ensureOpenSend(path, clientId, connectionToken);
@@ -237,23 +210,19 @@ export class WSChannel {
237
210
  }
238
211
 
239
212
  send(content: string) {
240
- this.inqueue(
241
- stringify({
242
- kind: 'data',
243
- id: this.id,
244
- content,
245
- }),
246
- );
213
+ this.inqueue({
214
+ kind: 'data',
215
+ id: this.id,
216
+ content,
217
+ });
247
218
  }
248
219
 
249
220
  sendBinary(data: Uint8Array) {
250
- this.inqueue(
251
- stringify({
252
- kind: 'binary',
253
- id: this.id,
254
- binary: data,
255
- }),
256
- );
221
+ this.inqueue({
222
+ kind: 'binary',
223
+ id: this.id,
224
+ binary: data,
225
+ });
257
226
  }
258
227
  onError() {}
259
228
  close(code?: number, reason?: string) {
@@ -286,6 +255,12 @@ export class WSChannel {
286
255
  return conn;
287
256
  }
288
257
 
258
+ listen() {
259
+ return this.connection.onMessage((data) => {
260
+ this.dispatch(data);
261
+ });
262
+ }
263
+
289
264
  dispose() {
290
265
  if (this.timer) {
291
266
  clearTimeout(this.timer);
@@ -293,6 +268,13 @@ export class WSChannel {
293
268
  this.sendQueue = [];
294
269
  this._disposables.dispose();
295
270
  }
271
+
272
+ ping() {
273
+ this.connection.send({
274
+ kind: 'ping',
275
+ id: this.id,
276
+ });
277
+ }
296
278
  }
297
279
 
298
280
  interface IWSServerChannelCreateOptions extends IWSChannelCreateOptions {
@@ -306,18 +288,17 @@ export class WSServerChannel extends WSChannel {
306
288
  messageQueue: ChannelMessage[] = [];
307
289
 
308
290
  clientId: string;
309
- constructor(public connection: IConnectionShape<Uint8Array>, options: IWSServerChannelCreateOptions) {
291
+ constructor(public connection: IConnectionShape<ChannelMessage>, options: IWSServerChannelCreateOptions) {
310
292
  super(connection, options);
311
293
  this.clientId = options.clientId;
312
294
  }
295
+
313
296
  serverReady(token: string) {
314
- this.connection.send(
315
- stringify({
316
- kind: 'server-ready',
317
- id: this.id,
318
- token,
319
- }),
320
- );
297
+ this.connection.send({
298
+ kind: 'server-ready',
299
+ id: this.id,
300
+ token,
301
+ });
321
302
  }
322
303
 
323
304
  dispatch(msg: ChannelMessage) {
@@ -328,128 +309,12 @@ export class WSServerChannel extends WSChannel {
328
309
  case 'binary':
329
310
  this.emitter.emit('binary', msg.binary);
330
311
  break;
312
+ case 'ping':
313
+ this.connection.send({
314
+ kind: 'pong',
315
+ id: this.id,
316
+ });
317
+ break;
331
318
  }
332
319
  }
333
320
  }
334
-
335
- export type ChannelMessage =
336
- | PingMessage
337
- | PongMessage
338
- | OpenMessage
339
- | ServerReadyMessage
340
- | DataMessage
341
- | BinaryMessage
342
- | CloseMessage
343
- | ErrorMessage;
344
-
345
- export const PingProtocol = Type.object('ping', {
346
- clientId: Type.string(),
347
- id: Type.string(),
348
- });
349
-
350
- export const PongProtocol = Type.object('pong', {
351
- clientId: Type.string(),
352
- id: Type.string(),
353
- });
354
-
355
- /**
356
- * `open` message is used to open a new channel.
357
- * `path` is used to identify which handler should be used to handle the channel.
358
- * `clientId` is used to identify the client.
359
- */
360
- export interface OpenMessage {
361
- kind: 'open';
362
- id: string;
363
- path: string;
364
- clientId: string;
365
- connectionToken: string;
366
- }
367
-
368
- export const OpenProtocol = Type.object('open', {
369
- clientId: Type.string(),
370
- id: Type.string(),
371
- path: Type.string(),
372
- connectionToken: Type.string(),
373
- });
374
-
375
- /**
376
- * when server receive a `open` message, it should reply a `server-ready` message.
377
- * this is indicate that the channel is ready to use.
378
- */
379
- export interface ServerReadyMessage {
380
- kind: 'server-ready';
381
- id: string;
382
- token: string;
383
- }
384
-
385
- export const ServerReadyProtocol = Type.object('server-ready', {
386
- id: Type.string(),
387
- token: Type.string(),
388
- });
389
-
390
- export enum ErrorMessageCode {
391
- ChannelNotFound = 1,
392
- }
393
-
394
- export interface ErrorMessage {
395
- kind: 'error';
396
- id: string;
397
- code: ErrorMessageCode;
398
- message: string;
399
- }
400
-
401
- export const ErrorProtocol = Type.object('error', {
402
- id: Type.string(),
403
- code: Type.uint16(),
404
- message: Type.string(),
405
- });
406
-
407
- export const DataProtocol = Type.object('data', {
408
- id: Type.string(),
409
- content: Type.string(),
410
- });
411
-
412
- export const BinaryProtocol = Type.object('binary', {
413
- id: Type.string(),
414
- binary: Type.binary(),
415
- });
416
-
417
- export const CloseProtocol = Type.object('close', {
418
- id: Type.string(),
419
- code: Type.uint32(),
420
- reason: Type.string(),
421
- });
422
-
423
- const serializer = oneOf([
424
- PingProtocol,
425
- PongProtocol,
426
- OpenProtocol,
427
- ServerReadyProtocol,
428
- DataProtocol,
429
- BinaryProtocol,
430
- CloseProtocol,
431
- ErrorProtocol,
432
- ]);
433
-
434
- export function stringify(obj: ChannelMessage): Uint8Array {
435
- return serializer.serialize(obj);
436
- }
437
-
438
- export function parse(input: Uint8Array): ChannelMessage {
439
- return serializer.deserialize(input) as any;
440
- }
441
-
442
- const _pingMessage: PingMessage = {
443
- kind: 'ping',
444
- id: '',
445
- clientId: '',
446
- };
447
-
448
- const _pongMessage: PongMessage = {
449
- kind: 'pong',
450
- id: '',
451
- clientId: '',
452
- };
453
-
454
- export const pingMessage = stringify(_pingMessage);
455
- export const pongMessage = stringify(_pongMessage);