@opensumi/ide-connection 2.27.3-rc-1713838390.0 → 2.27.3-rc-1713855854.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 (39) hide show
  1. package/lib/common/capturer.d.ts +21 -1
  2. package/lib/common/capturer.d.ts.map +1 -1
  3. package/lib/common/capturer.js +130 -4
  4. package/lib/common/capturer.js.map +1 -1
  5. package/lib/common/index.d.ts +0 -1
  6. package/lib/common/index.d.ts.map +1 -1
  7. package/lib/common/index.js +0 -1
  8. package/lib/common/index.js.map +1 -1
  9. package/lib/common/rpc/connection.d.ts +8 -2
  10. package/lib/common/rpc/connection.d.ts.map +1 -1
  11. package/lib/common/rpc/connection.js +17 -6
  12. package/lib/common/rpc/connection.js.map +1 -1
  13. package/lib/common/rpc-service/center.d.ts +1 -1
  14. package/lib/common/rpc-service/center.d.ts.map +1 -1
  15. package/lib/common/rpc-service/center.js.map +1 -1
  16. package/lib/common/rpc-service/proxy/base.d.ts +2 -11
  17. package/lib/common/rpc-service/proxy/base.d.ts.map +1 -1
  18. package/lib/common/rpc-service/proxy/base.js +3 -82
  19. package/lib/common/rpc-service/proxy/base.js.map +1 -1
  20. package/lib/common/rpc-service/proxy/json.d.ts +3 -1
  21. package/lib/common/rpc-service/proxy/json.d.ts.map +1 -1
  22. package/lib/common/rpc-service/proxy/json.js +12 -10
  23. package/lib/common/rpc-service/proxy/json.js.map +1 -1
  24. package/lib/common/rpc-service/proxy/sumi.d.ts.map +1 -1
  25. package/lib/common/rpc-service/proxy/sumi.js +3 -31
  26. package/lib/common/rpc-service/proxy/sumi.js.map +1 -1
  27. package/lib/common/ws-channel.d.ts +0 -1
  28. package/lib/common/ws-channel.d.ts.map +1 -1
  29. package/lib/common/ws-channel.js +0 -4
  30. package/lib/common/ws-channel.js.map +1 -1
  31. package/package.json +5 -5
  32. package/src/common/capturer.ts +169 -3
  33. package/src/common/index.ts +0 -1
  34. package/src/common/rpc/connection.ts +34 -7
  35. package/src/common/rpc-service/center.ts +2 -1
  36. package/src/common/rpc-service/proxy/base.ts +5 -101
  37. package/src/common/rpc-service/proxy/json.ts +14 -12
  38. package/src/common/rpc-service/proxy/sumi.ts +3 -30
  39. package/src/common/ws-channel.ts +0 -4
@@ -2,7 +2,7 @@ import { getDebugLogger } from '@opensumi/ide-core-common';
2
2
  import {
3
3
  CancellationToken,
4
4
  CancellationTokenSource,
5
- DisposableCollection,
5
+ DisposableStore,
6
6
  EventQueue,
7
7
  IDisposable,
8
8
  canceled,
@@ -10,6 +10,7 @@ import {
10
10
  } from '@opensumi/ide-utils';
11
11
  import { IReadableStream, isReadableStream, listenReadable } from '@opensumi/ide-utils/lib/stream';
12
12
 
13
+ import { Capturer } from '../capturer';
13
14
  import { BaseConnection, NetSocketConnection, WSWebSocketConnection } from '../connection';
14
15
  import { METHOD_NOT_REGISTERED } from '../constants';
15
16
  import { ILogger } from '../types';
@@ -34,10 +35,14 @@ const nullHeaders = {};
34
35
  export interface ISumiConnectionOptions {
35
36
  timeout?: number;
36
37
  logger?: ILogger;
38
+ /**
39
+ * The name of the connection, used for debugging(and can see in opensumi-devtools).
40
+ */
41
+ name?: string;
37
42
  }
38
43
 
39
44
  export class SumiConnection implements IDisposable {
40
- protected disposable = new DisposableCollection();
45
+ protected disposable = new DisposableStore();
41
46
 
42
47
  private _requestHandlers = new Map<string, TGenericRequestHandler<any>>();
43
48
  private _starRequestHandler: TRequestNotFoundHandler | undefined;
@@ -56,16 +61,24 @@ export class SumiConnection implements IDisposable {
56
61
  public io = new MessageIO();
57
62
  protected logger: ILogger;
58
63
 
64
+ protected capturer: Capturer;
65
+
59
66
  constructor(protected socket: BaseConnection<Uint8Array>, protected options: ISumiConnectionOptions = {}) {
60
67
  if (options.logger) {
61
68
  this.logger = options.logger;
62
69
  } else {
63
70
  this.logger = getDebugLogger();
64
71
  }
72
+
73
+ this.capturer = new Capturer(options.name || 'sumi');
74
+ this.disposable.add(this.capturer);
65
75
  }
66
76
 
67
77
  sendNotification(method: string, ...args: any[]) {
68
- this.socket.send(this.io.Notification(this._requestId++, method, nullHeaders, args));
78
+ const requestId = this._requestId++;
79
+
80
+ this.capturer.captureSendNotification(requestId, method, args);
81
+ this.socket.send(this.io.Notification(requestId, method, nullHeaders, args));
69
82
  }
70
83
 
71
84
  sendRequest(method: string, ...args: any[]) {
@@ -74,6 +87,8 @@ export class SumiConnection implements IDisposable {
74
87
 
75
88
  this._callbacks.set(requestId, (headers, error, result) => {
76
89
  if (error) {
90
+ this.traceRequestError(requestId, method, args, error);
91
+
77
92
  if (error === METHOD_NOT_REGISTERED) {
78
93
  // we should not treat `METHOD_NOT_REGISTERED` as an error.
79
94
  // it is a special case, it means the method is not registered on the other side.
@@ -81,11 +96,12 @@ export class SumiConnection implements IDisposable {
81
96
  return;
82
97
  }
83
98
 
84
- this.traceRequestError(method, args, error);
85
99
  reject(error);
86
100
  return;
87
101
  }
88
102
 
103
+ this.capturer.captureSendRequestResult(requestId, method, result);
104
+
89
105
  resolve(result);
90
106
  });
91
107
 
@@ -107,6 +123,8 @@ export class SumiConnection implements IDisposable {
107
123
  cancellationToken.onCancellationRequested(() => this.cancelRequest(requestId));
108
124
  }
109
125
 
126
+ this.capturer.captureSendRequest(requestId, method, args);
127
+
110
128
  this.socket.send(
111
129
  this.io.Request(
112
130
  requestId,
@@ -267,6 +285,8 @@ export class SumiConnection implements IDisposable {
267
285
 
268
286
  switch (opType) {
269
287
  case OperationType.Request: {
288
+ this.capturer.captureOnRequest(requestId, method, args);
289
+
270
290
  let promise: Promise<any>;
271
291
 
272
292
  try {
@@ -285,6 +305,8 @@ export class SumiConnection implements IDisposable {
285
305
  }
286
306
 
287
307
  const onSuccess = (result: any) => {
308
+ this.capturer.captureOnRequestResult(requestId, method, result);
309
+
288
310
  if (isReadableStream(result)) {
289
311
  const responseHeaders: IResponseHeaders = {
290
312
  chunked: true,
@@ -305,7 +327,8 @@ export class SumiConnection implements IDisposable {
305
327
  };
306
328
 
307
329
  const onError = (err: Error) => {
308
- this.traceRequestError(method, args, err);
330
+ this.traceRequestError(requestId, method, args, err);
331
+
309
332
  this.socket.send(this.io.Error(requestId, method, nullHeaders, err));
310
333
  this._cancellationTokenSources.delete(requestId);
311
334
  };
@@ -314,7 +337,10 @@ export class SumiConnection implements IDisposable {
314
337
  break;
315
338
  }
316
339
  case OperationType.Notification: {
340
+ this.capturer.captureOnNotification(requestId, method, args);
341
+
317
342
  const handler = this._notificationHandlers.get(method);
343
+
318
344
  if (handler) {
319
345
  handler(...args);
320
346
  } else if (this._starNotificationHandler) {
@@ -341,7 +367,7 @@ export class SumiConnection implements IDisposable {
341
367
  }
342
368
  });
343
369
  if (toDispose) {
344
- this.disposable.push(toDispose);
370
+ this.disposable.add(toDispose);
345
371
  }
346
372
  }
347
373
 
@@ -357,7 +383,8 @@ export class SumiConnection implements IDisposable {
357
383
  return new SumiConnection(new NetSocketConnection(socket), options);
358
384
  }
359
385
 
360
- private traceRequestError(method: string, args: any[], error: any) {
386
+ private traceRequestError(requestId: number, method: string, args: any[], error: any) {
387
+ this.capturer.captureSendRequestFail(requestId, method, error);
361
388
  this.logger.error(`Error handling request ${method} with args `, args, error);
362
389
  }
363
390
  }
@@ -1,5 +1,4 @@
1
1
  import { Deferred } from '@opensumi/ide-core-common';
2
- import { MessageConnection } from '@opensumi/vscode-jsonrpc';
3
2
 
4
3
  import { METHOD_NOT_REGISTERED } from '../constants';
5
4
  import { TSumiProtocol } from '../rpc';
@@ -10,6 +9,8 @@ import { ProxyJson, ProxySumi } from './proxy';
10
9
  import { ProxyBase } from './proxy/base';
11
10
  import { ProtocolRegistry, ServiceRegistry } from './registry';
12
11
 
12
+ import type { MessageConnection } from '@opensumi/vscode-jsonrpc';
13
+
13
14
  const safeProcess: { pid: string } = typeof process === 'undefined' ? { pid: 'unknown' } : (process as any);
14
15
 
15
16
  export class RPCServiceCenter {
@@ -1,6 +1,5 @@
1
- import { Deferred } from '@opensumi/ide-core-common';
1
+ import { Deferred, DisposableStore } from '@opensumi/ide-core-common';
2
2
 
3
- import { ICapturedMessage, MessageType, ResponseStatus, getCapturer } from '../../capturer';
4
3
  import { ILogger, IRPCServiceMap } from '../../types';
5
4
 
6
5
  import type { ServiceRegistry } from '../registry';
@@ -20,14 +19,13 @@ export abstract class ProxyBase<T extends IBaseConnection> {
20
19
 
21
20
  protected connectionPromise: Deferred<void> = new Deferred<void>();
22
21
 
22
+ protected _disposables = new DisposableStore();
23
+
23
24
  protected abstract engine: 'json' | 'sumi';
24
- capturer: (data: any) => void;
25
25
 
26
26
  constructor(public registry: ServiceRegistry, logger?: ILogger) {
27
27
  this.logger = logger || console;
28
28
 
29
- this.capturer = getCapturer();
30
-
31
29
  this.registry.onServicesUpdate((services) => {
32
30
  if (this.connection) {
33
31
  this.bindMethods(services);
@@ -35,105 +33,13 @@ export abstract class ProxyBase<T extends IBaseConnection> {
35
33
  });
36
34
  }
37
35
 
38
- // capture messages for opensumi devtools
39
- private capture(message: ICapturedMessage): void {
40
- this.capturer({
41
- ...message,
42
- engine: this.engine,
43
- });
44
- }
45
-
46
36
  protected nextRequestId() {
47
37
  return String(requestId++);
48
38
  }
49
39
 
50
- protected captureOnRequest(requestId: string, serviceMethod: string, args: any[]): void {
51
- if (!this.capturer) {
52
- return;
53
- }
54
- this.capture({ type: MessageType.OnRequest, requestId, serviceMethod, arguments: args });
55
- }
56
-
57
- protected captureOnRequestResult(requestId: string, serviceMethod: string, data: any): void {
58
- if (!this.capturer) {
59
- return;
60
- }
61
- this.capture({
62
- type: MessageType.OnRequestResult,
63
- status: ResponseStatus.Success,
64
- requestId,
65
- serviceMethod,
66
- data,
67
- });
68
- }
69
-
70
- protected captureOnRequestFail(requestId: string, serviceMethod: string, error: any): void {
71
- if (!this.capturer) {
72
- return;
73
- }
74
-
75
- this.logger.warn(`request exec ${serviceMethod} error`, error);
76
-
77
- this.capture({
78
- type: MessageType.OnRequestResult,
79
- status: ResponseStatus.Fail,
80
- requestId,
81
- serviceMethod,
82
- error,
83
- });
84
- }
85
-
86
- protected captureOnNotification(serviceMethod: string, args: any[]): void {
87
- if (!this.capturer) {
88
- return;
89
- }
90
- this.capture({ type: MessageType.OnNotification, serviceMethod, arguments: args });
91
- }
92
-
93
- protected captureSendRequest(requestId: string, serviceMethod: string, args: any[]): void {
94
- if (!this.capturer) {
95
- return;
96
- }
97
- this.capture({ type: MessageType.SendRequest, requestId, serviceMethod, arguments: args });
98
- }
99
-
100
- protected captureSendRequestResult(requestId: string, serviceMethod: string, data: any): void {
101
- if (!this.capturer) {
102
- return;
103
- }
104
-
105
- this.capture({
106
- type: MessageType.RequestResult,
107
- status: ResponseStatus.Success,
108
- requestId,
109
- serviceMethod,
110
- data,
111
- });
112
- }
113
-
114
- protected captureSendRequestFail(requestId: string, serviceMethod: string, error: any): void {
115
- if (!this.capturer) {
116
- return;
117
- }
118
-
119
- this.capture({
120
- type: MessageType.RequestResult,
121
- status: ResponseStatus.Fail,
122
- requestId,
123
- serviceMethod,
124
- error,
125
- });
126
- }
127
-
128
- protected captureSendNotification(serviceMethod: string, args: any[]): void {
129
- if (!this.capturer) {
130
- return;
131
- }
132
- this.capture({ type: MessageType.SendNotification, serviceMethod, arguments: args });
133
- }
134
-
135
40
  listen(connection: T): void {
136
41
  this.connection = connection;
42
+ this._disposables.add(this.connection);
137
43
  this.bindMethods(this.registry.methods());
138
44
 
139
45
  connection.listen();
@@ -145,9 +51,7 @@ export abstract class ProxyBase<T extends IBaseConnection> {
145
51
  }
146
52
 
147
53
  dispose(): void {
148
- if (this.connection) {
149
- this.connection.dispose();
150
- }
54
+ this._disposables.dispose();
151
55
  }
152
56
 
153
57
  public abstract invoke(prop: string, ...args: any[]): Promise<any>;
@@ -1,9 +1,10 @@
1
- import { MessageConnection } from '@opensumi/vscode-jsonrpc';
2
-
1
+ import { Capturer } from '../../capturer';
3
2
  import { METHOD_NOT_REGISTERED } from '../../constants';
4
3
 
5
4
  import { ProxyBase } from './base';
6
5
 
6
+ import type { MessageConnection } from '@opensumi/vscode-jsonrpc';
7
+
7
8
  interface IRPCResult {
8
9
  error: boolean;
9
10
  data: any;
@@ -11,12 +12,13 @@ interface IRPCResult {
11
12
 
12
13
  export class ProxyJson extends ProxyBase<MessageConnection> {
13
14
  protected engine = 'json' as const;
15
+ protected capturer = this._disposables.add(new Capturer(this.engine));
14
16
 
15
17
  protected bindMethods(methods: string[]): void {
16
18
  for (const method of methods) {
17
19
  if (method.startsWith('on')) {
18
20
  this.connection.onNotification(method, async (...args: any[]) => {
19
- this.captureOnNotification(method, args);
21
+ this.capturer.captureOnNotification('_', method, args);
20
22
  try {
21
23
  await this.registry.invoke(method, ...this.serializeArguments(args));
22
24
  } catch (e) {
@@ -26,19 +28,19 @@ export class ProxyJson extends ProxyBase<MessageConnection> {
26
28
  } else {
27
29
  this.connection.onRequest(method, async (...args: any[]) => {
28
30
  const requestId = this.nextRequestId();
29
- this.captureOnRequest(requestId, method, args);
31
+ this.capturer.captureOnRequest(requestId, method, args);
30
32
 
31
33
  try {
32
34
  const result = await this.registry.invoke(method, ...this.serializeArguments(args));
33
35
 
34
- this.captureOnRequestResult(requestId, method, result);
36
+ this.capturer.captureOnRequestResult(requestId, method, result);
35
37
 
36
38
  return {
37
39
  error: false,
38
40
  data: result,
39
41
  };
40
42
  } catch (e) {
41
- this.captureOnRequestFail(requestId, method, e);
43
+ this.capturer.captureOnRequestFail(requestId, method, e);
42
44
 
43
45
  return {
44
46
  error: true,
@@ -63,7 +65,7 @@ export class ProxyJson extends ProxyBase<MessageConnection> {
63
65
 
64
66
  // 调用方法为 on 开头时,作为单项通知
65
67
  if (prop.startsWith('on')) {
66
- this.captureSendNotification(prop, args);
68
+ this.capturer.captureSendNotification('_', prop, args);
67
69
  if (isSingleArray) {
68
70
  this.connection.sendNotification(prop, [...args]);
69
71
  } else {
@@ -81,7 +83,7 @@ export class ProxyJson extends ProxyBase<MessageConnection> {
81
83
  requestResult = this.connection.sendRequest(prop, ...args) as Promise<any>;
82
84
  }
83
85
 
84
- this.captureSendRequest(requestId, prop, args);
86
+ this.capturer.captureSendRequest(requestId, prop, args);
85
87
 
86
88
  const result: IRPCResult = await requestResult;
87
89
 
@@ -91,10 +93,10 @@ export class ProxyJson extends ProxyBase<MessageConnection> {
91
93
  error.stack = result.data.stack;
92
94
  }
93
95
 
94
- this.captureSendRequestFail(requestId, prop, result.data);
96
+ this.capturer.captureSendRequestFail(requestId, prop, result.data);
95
97
  throw error;
96
98
  } else {
97
- this.captureSendRequestResult(requestId, prop, result.data);
99
+ this.capturer.captureSendRequestResult(requestId, prop, result.data);
98
100
  return result.data;
99
101
  }
100
102
  }
@@ -128,11 +130,11 @@ export class ProxyJson extends ProxyBase<MessageConnection> {
128
130
  connection.onRequest((method) => {
129
131
  if (!this.registry.has(method)) {
130
132
  const requestId = this.nextRequestId();
131
- this.captureOnRequest(requestId, method, []);
133
+ this.capturer.captureOnRequest(requestId, method, []);
132
134
  const result = {
133
135
  data: METHOD_NOT_REGISTERED,
134
136
  };
135
- this.captureOnRequestFail(requestId, method, result.data);
137
+ this.capturer.captureOnRequestFail(requestId, method, result.data);
136
138
  return result;
137
139
  }
138
140
  });
@@ -10,7 +10,6 @@ export class ProxySumi extends ProxyBase<SumiConnection> {
10
10
  for (const method of methods) {
11
11
  if (method.startsWith('on')) {
12
12
  this.connection.onNotification(method, async (...args: any[]) => {
13
- this.captureOnNotification(method, args);
14
13
  try {
15
14
  await this.registry.invoke(method, ...args);
16
15
  } catch (e) {
@@ -18,19 +17,7 @@ export class ProxySumi extends ProxyBase<SumiConnection> {
18
17
  }
19
18
  });
20
19
  } else {
21
- this.connection.onRequest(method, async (...args: any[]) => {
22
- const requestId = this.nextRequestId();
23
- this.captureOnRequest(requestId, method, args);
24
-
25
- try {
26
- const result = await this.registry.invoke(method, ...args);
27
- this.captureOnRequestResult(requestId, method, result);
28
- return result;
29
- } catch (e) {
30
- this.captureOnRequestFail(requestId, method, e);
31
- throw e;
32
- }
33
- });
20
+ this.connection.onRequest(method, async (...args: any[]) => await this.registry.invoke(method, ...args));
34
21
  }
35
22
  }
36
23
  }
@@ -40,29 +27,15 @@ export class ProxySumi extends ProxyBase<SumiConnection> {
40
27
 
41
28
  // 调用方法为 on 开头时,作为单项通知
42
29
  if (prop.startsWith('on')) {
43
- this.captureSendNotification(prop, args);
44
30
  this.connection.sendNotification(prop, ...args);
45
31
  } 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
- }
32
+ return await this.connection.sendRequest(prop, ...args);
57
33
  }
58
34
  }
59
35
 
60
36
  listen(connection: SumiConnection): void {
61
37
  super.listen(connection);
62
- connection.onRequestNotFound((method) => {
63
- const requestId = this.nextRequestId();
64
- this.captureOnRequest(requestId, method, []);
65
- this.captureOnRequestFail(requestId, method, METHOD_NOT_REGISTERED);
38
+ connection.onRequestNotFound(() => {
66
39
  throw METHOD_NOT_REGISTERED;
67
40
  });
68
41
  }
@@ -5,7 +5,6 @@ import { DisposableCollection } from '@opensumi/ide-core-common';
5
5
 
6
6
  import { IConnectionShape } from './connection/types';
7
7
  import { oneOf7 } from './fury-extends/one-of';
8
- import { createWebSocketConnection } from './message';
9
8
  import { ISumiConnectionOptions, SumiConnection } from './rpc/connection';
10
9
  import { ILogger } from './types';
11
10
 
@@ -213,9 +212,6 @@ export class WSChannel {
213
212
  onceClose(cb: (code: number, reason: string) => void) {
214
213
  return this.emitter.once('close', cb);
215
214
  }
216
- createMessageConnection() {
217
- return createWebSocketConnection(this);
218
- }
219
215
 
220
216
  createConnection() {
221
217
  return {