@opensumi/ide-connection 2.27.3-rc-1708399099.0 → 2.27.3-rc-1710489030.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/README.md +1 -1
  2. package/lib/browser/ws-channel-handler.d.ts +1 -1
  3. package/lib/browser/ws-channel-handler.d.ts.map +1 -1
  4. package/lib/browser/ws-channel-handler.js +23 -33
  5. package/lib/browser/ws-channel-handler.js.map +1 -1
  6. package/lib/common/buffers/buffers.d.ts +1 -0
  7. package/lib/common/buffers/buffers.d.ts.map +1 -1
  8. package/lib/common/buffers/buffers.js +3 -3
  9. package/lib/common/buffers/buffers.js.map +1 -1
  10. package/lib/common/{utils.d.ts → capturer.d.ts} +1 -19
  11. package/lib/common/capturer.d.ts.map +1 -0
  12. package/lib/common/capturer.js +26 -0
  13. package/lib/common/capturer.js.map +1 -0
  14. package/lib/common/connection/drivers/frame-decoder.d.ts +40 -1
  15. package/lib/common/connection/drivers/frame-decoder.d.ts.map +1 -1
  16. package/lib/common/connection/drivers/frame-decoder.js +9 -10
  17. package/lib/common/connection/drivers/frame-decoder.js.map +1 -1
  18. package/lib/common/connection/drivers/index.d.ts +0 -1
  19. package/lib/common/connection/drivers/index.d.ts.map +1 -1
  20. package/lib/common/connection/drivers/index.js +0 -1
  21. package/lib/common/connection/drivers/index.js.map +1 -1
  22. package/lib/common/connection/drivers/message-port.d.ts.map +1 -1
  23. package/lib/common/connection/drivers/message-port.js +1 -4
  24. package/lib/common/connection/drivers/message-port.js.map +1 -1
  25. package/lib/common/connection/drivers/node-message-port.d.ts +1 -1
  26. package/lib/common/connection/drivers/node-message-port.d.ts.map +1 -1
  27. package/lib/common/connection/drivers/node-message-port.js.map +1 -1
  28. package/lib/common/connection/drivers/reconnecting-websocket.d.ts.map +1 -1
  29. package/lib/common/connection/drivers/reconnecting-websocket.js +1 -1
  30. package/lib/common/connection/drivers/reconnecting-websocket.js.map +1 -1
  31. package/lib/common/connection/drivers/socket.d.ts +3 -10
  32. package/lib/common/connection/drivers/socket.d.ts.map +1 -1
  33. package/lib/common/connection/drivers/socket.js +3 -36
  34. package/lib/common/connection/drivers/socket.js.map +1 -1
  35. package/lib/common/connection/drivers/stream.d.ts +17 -0
  36. package/lib/common/connection/drivers/stream.d.ts.map +1 -0
  37. package/lib/common/connection/drivers/stream.js +70 -0
  38. package/lib/common/connection/drivers/stream.js.map +1 -0
  39. package/lib/common/connection/drivers/ws-websocket.d.ts +1 -1
  40. package/lib/common/connection/drivers/ws-websocket.d.ts.map +1 -1
  41. package/lib/common/connection/drivers/ws-websocket.js.map +1 -1
  42. package/lib/common/fury-extends/any.d.ts +10 -7
  43. package/lib/common/fury-extends/any.d.ts.map +1 -1
  44. package/lib/common/fury-extends/any.js +126 -105
  45. package/lib/common/fury-extends/any.js.map +1 -1
  46. package/lib/common/fury-extends/one-of.d.ts +10 -5
  47. package/lib/common/fury-extends/one-of.d.ts.map +1 -1
  48. package/lib/common/fury-extends/one-of.js +65 -30
  49. package/lib/common/fury-extends/one-of.js.map +1 -1
  50. package/lib/common/fury-extends/shared.d.ts +2 -0
  51. package/lib/common/fury-extends/shared.d.ts.map +1 -1
  52. package/lib/common/fury-extends/shared.js.map +1 -1
  53. package/lib/common/index.d.ts +2 -2
  54. package/lib/common/index.d.ts.map +1 -1
  55. package/lib/common/index.js +2 -2
  56. package/lib/common/index.js.map +1 -1
  57. package/lib/common/message.d.ts +1 -1
  58. package/lib/common/message.d.ts.map +1 -1
  59. package/lib/common/rpc/connection.d.ts +31 -15
  60. package/lib/common/rpc/connection.d.ts.map +1 -1
  61. package/lib/common/rpc/connection.js +206 -138
  62. package/lib/common/rpc/connection.js.map +1 -1
  63. package/lib/common/rpc/index.d.ts +1 -1
  64. package/lib/common/rpc/index.d.ts.map +1 -1
  65. package/lib/common/rpc/index.js +1 -1
  66. package/lib/common/rpc/index.js.map +1 -1
  67. package/lib/common/rpc/message-io.d.ts +61 -0
  68. package/lib/common/rpc/message-io.d.ts.map +1 -0
  69. package/lib/common/rpc/message-io.js +159 -0
  70. package/lib/common/rpc/message-io.js.map +1 -0
  71. package/lib/common/rpc/multiplexer.d.ts +3 -0
  72. package/lib/common/rpc/multiplexer.d.ts.map +1 -1
  73. package/lib/common/rpc/multiplexer.js +3 -0
  74. package/lib/common/rpc/multiplexer.js.map +1 -1
  75. package/lib/common/rpc/types.d.ts +26 -5
  76. package/lib/common/rpc/types.d.ts.map +1 -1
  77. package/lib/common/rpc-service/center.d.ts +6 -3
  78. package/lib/common/rpc-service/center.d.ts.map +1 -1
  79. package/lib/common/rpc-service/center.js +39 -31
  80. package/lib/common/rpc-service/center.js.map +1 -1
  81. package/lib/common/rpc-service/proxy/base.d.ts +5 -3
  82. package/lib/common/rpc-service/proxy/base.d.ts.map +1 -1
  83. package/lib/common/rpc-service/proxy/base.js +56 -17
  84. package/lib/common/rpc-service/proxy/base.js.map +1 -1
  85. package/lib/common/rpc-service/proxy/index.d.ts +1 -3
  86. package/lib/common/rpc-service/proxy/index.d.ts.map +1 -1
  87. package/lib/common/rpc-service/proxy/index.js +1 -3
  88. package/lib/common/rpc-service/proxy/index.js.map +1 -1
  89. package/lib/common/rpc-service/proxy/{legacy.d.ts → json.d.ts} +5 -5
  90. package/lib/common/rpc-service/proxy/json.d.ts.map +1 -0
  91. package/lib/common/rpc-service/proxy/{legacy.js → json.js} +46 -56
  92. package/lib/common/rpc-service/proxy/json.js.map +1 -0
  93. package/lib/common/rpc-service/proxy/sumi.d.ts +1 -1
  94. package/lib/common/rpc-service/proxy/sumi.d.ts.map +1 -1
  95. package/lib/common/rpc-service/proxy/sumi.js +25 -37
  96. package/lib/common/rpc-service/proxy/sumi.js.map +1 -1
  97. package/lib/common/rpc-service/{proxy/registry.d.ts → registry.d.ts} +12 -1
  98. package/lib/common/rpc-service/registry.d.ts.map +1 -0
  99. package/lib/common/rpc-service/registry.js +99 -0
  100. package/lib/common/rpc-service/registry.js.map +1 -0
  101. package/lib/common/rpc-service/stub.js +4 -6
  102. package/lib/common/rpc-service/stub.js.map +1 -1
  103. package/lib/common/{ext-rpc-protocol.d.ts → rpcProtocol.d.ts} +2 -2
  104. package/lib/common/rpcProtocol.d.ts.map +1 -0
  105. package/lib/common/{ext-rpc-protocol.js → rpcProtocol.js} +5 -6
  106. package/lib/common/rpcProtocol.js.map +1 -0
  107. package/lib/common/server-handler.d.ts +35 -0
  108. package/lib/common/server-handler.d.ts.map +1 -0
  109. package/lib/common/server-handler.js +165 -0
  110. package/lib/common/server-handler.js.map +1 -0
  111. package/lib/common/types.d.ts +14 -0
  112. package/lib/common/types.d.ts.map +1 -1
  113. package/lib/common/ws-channel.d.ts +6 -10
  114. package/lib/common/ws-channel.d.ts.map +1 -1
  115. package/lib/common/ws-channel.js +16 -15
  116. package/lib/common/ws-channel.js.map +1 -1
  117. package/lib/electron/channel-handler.d.ts +14 -0
  118. package/lib/electron/channel-handler.d.ts.map +1 -0
  119. package/lib/electron/channel-handler.js +26 -0
  120. package/lib/electron/channel-handler.js.map +1 -0
  121. package/lib/electron/index.d.ts +2 -0
  122. package/lib/electron/index.d.ts.map +1 -0
  123. package/lib/electron/index.js +5 -0
  124. package/lib/electron/index.js.map +1 -0
  125. package/lib/node/common-channel-handler.d.ts +6 -25
  126. package/lib/node/common-channel-handler.d.ts.map +1 -1
  127. package/lib/node/common-channel-handler.js +9 -151
  128. package/lib/node/common-channel-handler.js.map +1 -1
  129. package/package.json +5 -5
  130. package/src/browser/ws-channel-handler.ts +26 -40
  131. package/src/common/buffers/buffers.ts +1 -1
  132. package/src/common/capturer.ts +36 -0
  133. package/src/common/connection/drivers/frame-decoder.ts +11 -11
  134. package/src/common/connection/drivers/index.ts +0 -1
  135. package/src/common/connection/drivers/message-port.ts +1 -4
  136. package/src/common/connection/drivers/node-message-port.ts +2 -2
  137. package/src/common/connection/drivers/reconnecting-websocket.ts +3 -2
  138. package/src/common/connection/drivers/socket.ts +4 -42
  139. package/src/common/connection/drivers/stream.ts +76 -0
  140. package/src/common/connection/drivers/ws-websocket.ts +2 -2
  141. package/src/common/fury-extends/any.ts +122 -102
  142. package/src/common/fury-extends/one-of.ts +79 -31
  143. package/src/common/fury-extends/shared.ts +3 -0
  144. package/src/common/index.ts +2 -2
  145. package/src/common/message.ts +1 -1
  146. package/src/common/rpc/connection.ts +228 -166
  147. package/src/common/rpc/index.ts +1 -1
  148. package/src/common/rpc/message-io.ts +223 -0
  149. package/src/common/rpc/multiplexer.ts +3 -0
  150. package/src/common/rpc/types.ts +30 -5
  151. package/src/common/rpc-service/center.ts +37 -31
  152. package/src/common/rpc-service/proxy/base.ts +59 -12
  153. package/src/common/rpc-service/proxy/index.ts +1 -3
  154. package/src/common/rpc-service/proxy/{legacy.ts → json.ts} +47 -57
  155. package/src/common/rpc-service/proxy/sumi.ts +23 -35
  156. package/src/common/rpc-service/registry.ts +125 -0
  157. package/src/common/rpc-service/stub.ts +6 -6
  158. package/src/common/{ext-rpc-protocol.ts → rpcProtocol.ts} +2 -2
  159. package/src/common/server-handler.ts +183 -0
  160. package/src/common/types.ts +13 -0
  161. package/src/common/ws-channel.ts +21 -23
  162. package/src/electron/channel-handler.ts +26 -0
  163. package/src/electron/index.ts +1 -0
  164. package/src/node/common-channel-handler.ts +10 -165
  165. package/lib/common/connection/drivers/utils.d.ts +0 -12
  166. package/lib/common/connection/drivers/utils.d.ts.map +0 -1
  167. package/lib/common/connection/drivers/utils.js +0 -49
  168. package/lib/common/connection/drivers/utils.js.map +0 -1
  169. package/lib/common/ext-rpc-protocol.d.ts.map +0 -1
  170. package/lib/common/ext-rpc-protocol.js.map +0 -1
  171. package/lib/common/rpc/packet.d.ts +0 -65
  172. package/lib/common/rpc/packet.d.ts.map +0 -1
  173. package/lib/common/rpc/packet.js +0 -82
  174. package/lib/common/rpc/packet.js.map +0 -1
  175. package/lib/common/rpc/protocol-repository.d.ts +0 -32
  176. package/lib/common/rpc/protocol-repository.d.ts.map +0 -1
  177. package/lib/common/rpc/protocol-repository.js +0 -118
  178. package/lib/common/rpc/protocol-repository.js.map +0 -1
  179. package/lib/common/rpc/utils.d.ts +0 -2
  180. package/lib/common/rpc/utils.d.ts.map +0 -1
  181. package/lib/common/rpc/utils.js +0 -10
  182. package/lib/common/rpc/utils.js.map +0 -1
  183. package/lib/common/rpc-service/proxy/invoker.d.ts +0 -14
  184. package/lib/common/rpc-service/proxy/invoker.d.ts.map +0 -1
  185. package/lib/common/rpc-service/proxy/invoker.js +0 -34
  186. package/lib/common/rpc-service/proxy/invoker.js.map +0 -1
  187. package/lib/common/rpc-service/proxy/legacy.d.ts.map +0 -1
  188. package/lib/common/rpc-service/proxy/legacy.js.map +0 -1
  189. package/lib/common/rpc-service/proxy/registry.d.ts.map +0 -1
  190. package/lib/common/rpc-service/proxy/registry.js +0 -46
  191. package/lib/common/rpc-service/proxy/registry.js.map +0 -1
  192. package/lib/common/utils.d.ts.map +0 -1
  193. package/lib/common/utils.js +0 -57
  194. package/lib/common/utils.js.map +0 -1
  195. package/src/common/connection/drivers/utils.ts +0 -52
  196. package/src/common/rpc/packet.ts +0 -104
  197. package/src/common/rpc/protocol-repository.ts +0 -180
  198. package/src/common/rpc/utils.ts +0 -5
  199. package/src/common/rpc-service/proxy/invoker.ts +0 -45
  200. package/src/common/rpc-service/proxy/registry.ts +0 -56
  201. package/src/common/utils.ts +0 -80
@@ -1,45 +1,35 @@
1
- import type net from 'net';
2
-
3
- import type { WebSocket } from 'ws';
4
-
5
- import { EventEmitter } from '@opensumi/events';
1
+ import { getDebugLogger } from '@opensumi/ide-core-common';
6
2
  import {
3
+ CancellationToken,
4
+ CancellationTokenSource,
7
5
  DisposableCollection,
6
+ EventQueue,
8
7
  IDisposable,
9
- parseError,
10
- CancellationToken,
11
8
  canceled,
12
- CancellationTokenSource,
13
- isPromise,
9
+ parseError,
14
10
  } from '@opensumi/ide-utils';
11
+ import { IReadableStream, isReadableStream, listenReadable } from '@opensumi/ide-utils/lib/stream';
15
12
 
16
13
  import { BaseConnection, NetSocketConnection, WSWebSocketConnection } from '../connection';
17
14
  import { METHOD_NOT_REGISTERED } from '../constants';
18
15
  import { ILogger } from '../types';
19
16
 
20
17
  import { MethodTimeoutError } from './errors';
18
+ import { MessageIO, OperationType, Status } from './message-io';
21
19
  import {
22
- BodyCodec,
23
- ErrorCode,
24
- OperationType,
25
- MessageIO,
26
- requestHeadersSerializer,
27
- reader,
28
20
  IRequestHeaders,
29
- } from './packet';
30
- import { ProtocolRepository } from './protocol-repository';
31
- import {
21
+ IResponseHeaders,
32
22
  TGenericNotificationHandler,
33
23
  TGenericRequestHandler,
34
- TOnNotificationNotFoundHandler,
35
- TOnRequestNotFoundHandler,
24
+ TNotificationNotFoundHandler,
36
25
  TRequestCallback,
26
+ TRequestNotFoundHandler,
37
27
  } from './types';
38
- import { assert } from './utils';
39
28
 
40
- const nullHeaders = {};
29
+ import type net from 'net';
30
+ import type { WebSocket } from 'ws';
41
31
 
42
- const star = '*';
32
+ const nullHeaders = {};
43
33
 
44
34
  export interface ISumiConnectionOptions {
45
35
  timeout?: number;
@@ -49,12 +39,10 @@ export interface ISumiConnectionOptions {
49
39
  export class SumiConnection implements IDisposable {
50
40
  protected disposable = new DisposableCollection();
51
41
 
52
- private _requestEmitter = new EventEmitter<{
53
- [key: string]: [requestId: number, method: string, headers: Record<string, any>, args: any[]];
54
- }>();
55
- private _notificationEmitter = new EventEmitter<{
56
- [key: string]: [requestId: number, method: string, headers: Record<string, any>, args: any[]];
57
- }>();
42
+ private _requestHandlers = new Map<string, TGenericRequestHandler<any>>();
43
+ private _starRequestHandler: TRequestNotFoundHandler | undefined;
44
+ private _notificationHandlers = new Map<string, TGenericNotificationHandler>();
45
+ private _starNotificationHandler: TNotificationNotFoundHandler | undefined;
58
46
 
59
47
  private _requestId = 0;
60
48
  private _callbacks = new Map<number, TRequestCallback>();
@@ -63,39 +51,41 @@ export class SumiConnection implements IDisposable {
63
51
  private readonly _cancellationTokenSources = new Map<number, CancellationTokenSource>();
64
52
  private readonly _knownCanceledRequests = new Set<number>();
65
53
 
66
- public protocolRepository = new ProtocolRepository();
67
- protected logger: ILogger = console;
54
+ protected activeRequestPool = new Map<number, ActiveRequest>();
55
+
56
+ public io = new MessageIO();
57
+ protected logger: ILogger;
68
58
 
69
59
  constructor(protected socket: BaseConnection<Uint8Array>, protected options: ISumiConnectionOptions = {}) {
70
60
  if (options.logger) {
71
61
  this.logger = options.logger;
62
+ } else {
63
+ this.logger = getDebugLogger();
72
64
  }
73
65
  }
74
66
 
75
67
  sendNotification(method: string, ...args: any[]) {
76
- const processor = this.protocolRepository.getProcessor(method);
77
- const payload = processor.serializeRequest(args);
78
- this.socket.send(MessageIO.Request(this._requestId++, OperationType.Notification, method, nullHeaders, payload));
68
+ this.socket.send(this.io.Notification(this._requestId++, method, nullHeaders, args));
79
69
  }
80
70
 
81
71
  sendRequest(method: string, ...args: any[]) {
82
72
  return new Promise<any>((resolve, reject) => {
83
73
  const requestId = this._requestId++;
84
74
 
85
- const processor = this.protocolRepository.getProcessor(method);
86
-
87
- this._callbacks.set(requestId, (headers, error, buffer) => {
75
+ this._callbacks.set(requestId, (headers, error, result) => {
88
76
  if (error) {
89
77
  if (error === METHOD_NOT_REGISTERED) {
78
+ // we should not treat `METHOD_NOT_REGISTERED` as an error.
79
+ // it is a special case, it means the method is not registered on the other side.
90
80
  resolve(error);
91
81
  return;
92
82
  }
93
83
 
84
+ this.traceRequestError(method, args, error);
94
85
  reject(error);
95
86
  return;
96
87
  }
97
88
 
98
- const result = processor.deserializeResult(buffer);
99
89
  resolve(result);
100
90
  });
101
91
 
@@ -117,37 +107,21 @@ export class SumiConnection implements IDisposable {
117
107
  cancellationToken.onCancellationRequested(() => this.cancelRequest(requestId));
118
108
  }
119
109
 
120
- const payload = processor.serializeRequest(args);
121
110
  this.socket.send(
122
- MessageIO.Request(
111
+ this.io.Request(
123
112
  requestId,
124
- OperationType.Request,
125
113
  method,
126
114
  {
127
- cancelable: cancellationToken ? true : false,
115
+ cancelable: Boolean(cancellationToken) || undefined,
128
116
  },
129
- payload,
117
+ args,
130
118
  ),
131
119
  );
132
120
  });
133
121
  }
134
122
 
135
- onNotification(method: string, handler: TGenericNotificationHandler): IDisposable {
136
- const handlerWrapper = (requestId: number, method: string, headers: Record<string, any>, args: any[]) => {
137
- handler(...args);
138
- };
139
- return this._notificationEmitter.on(method, handlerWrapper);
140
- }
141
-
142
- onNotificationNotFound(handler: TOnNotificationNotFoundHandler): IDisposable {
143
- const handlerWrapper = (requestId: number, method: string, headers: Record<string, any>, args: any[]) => {
144
- handler(method, args);
145
- };
146
- return this._notificationEmitter.on(star, handlerWrapper);
147
- }
148
-
149
123
  cancelRequest(requestId: number) {
150
- this.socket.send(MessageIO.Cancel(requestId));
124
+ this.socket.send(this.io.Cancel(requestId));
151
125
  }
152
126
 
153
127
  private _handleTimeout(method: string, requestId: number) {
@@ -161,72 +135,52 @@ export class SumiConnection implements IDisposable {
161
135
  callback(nullHeaders, new MethodTimeoutError(method));
162
136
  }
163
137
 
164
- private runRequestHandler<T extends (...args: any[]) => any>(
165
- requestId: number,
166
- method: string,
167
- args: any[],
168
- handler: T,
169
- ) {
170
- let result: any;
171
- let error: Error | undefined;
172
- const processor = this.protocolRepository.getProcessor(method);
173
-
174
- try {
175
- result = handler(...args);
176
- } catch (err) {
177
- error = err;
178
- }
179
-
180
- if (error) {
181
- this.socket.send(MessageIO.Error(requestId, ErrorCode.Err, nullHeaders, error));
182
- this._cancellationTokenSources.delete(requestId);
183
- } else if (isPromise(result)) {
184
- result
185
- .then((result) => {
186
- const payload = processor.serializeResult(result);
187
- this.socket.send(MessageIO.Response(requestId, nullHeaders, payload));
188
- this._cancellationTokenSources.delete(requestId);
189
- })
190
- .catch((err) => {
191
- this.socket.send(MessageIO.Error(requestId, ErrorCode.Err, nullHeaders, err));
192
- this._cancellationTokenSources.delete(requestId);
193
- });
194
- } else {
195
- const payload = processor.serializeResult(result);
196
- this.socket.send(MessageIO.Response(requestId, nullHeaders, payload));
197
- this._cancellationTokenSources.delete(requestId);
198
- }
199
- }
200
-
201
138
  onRequest<T = any>(method: string, handler: TGenericRequestHandler<T>): IDisposable {
202
- const handlerWrapper = (requestId: number, method: string, headers: Record<string, any>, args: any[]) => {
203
- this.runRequestHandler(requestId, method, args, handler);
139
+ this._requestHandlers.set(method, handler);
140
+ return {
141
+ dispose: () => {
142
+ this._requestHandlers.delete(method);
143
+ },
204
144
  };
205
- return this._requestEmitter.on(method, handlerWrapper);
206
145
  }
207
146
 
208
- onRequestNotFound(handler: TOnRequestNotFoundHandler): IDisposable {
209
- const handlerWrapper = (requestId: number, method: string, headers: Record<string, any>, args: any[]) => {
210
- this.runRequestHandler(requestId, method, [method, args], handler);
147
+ onRequestNotFound(handler: TRequestNotFoundHandler): IDisposable {
148
+ this._starRequestHandler = handler;
149
+ return {
150
+ dispose: () => {
151
+ this._starRequestHandler = undefined;
152
+ },
211
153
  };
154
+ }
212
155
 
213
- return this._requestEmitter.on(star, handlerWrapper);
156
+ onNotification(method: string, handler: TGenericNotificationHandler): IDisposable {
157
+ this._notificationHandlers.set(method, handler);
158
+ return {
159
+ dispose: () => {
160
+ this._notificationHandlers.delete(method);
161
+ },
162
+ };
214
163
  }
215
164
 
216
- setProtocolRepository(protocolRepository: ProtocolRepository) {
217
- this.protocolRepository = protocolRepository;
165
+ onNotificationNotFound(handler: TNotificationNotFoundHandler): IDisposable {
166
+ this._starNotificationHandler = handler;
167
+ return {
168
+ dispose: () => {
169
+ this._starNotificationHandler = undefined;
170
+ },
171
+ };
218
172
  }
219
173
 
220
174
  listen() {
175
+ const { reader } = this.io;
176
+
221
177
  const toDispose = this.socket.onMessage((data) => {
222
178
  reader.reset(data);
223
179
  // skip version, currently only have version 1
224
180
  reader.skip(1);
225
181
 
226
- const rpcType = reader.uint8();
227
-
182
+ const opType = reader.uint8() as OperationType;
228
183
  const requestId = reader.uint32();
229
- const codec = reader.uint8();
230
184
 
231
185
  if (this._timeoutHandles.has(requestId)) {
232
186
  // Ignore some jest test scenarios where clearTimeout is not defined.
@@ -237,41 +191,59 @@ export class SumiConnection implements IDisposable {
237
191
  this._timeoutHandles.delete(requestId);
238
192
  }
239
193
 
240
- switch (rpcType) {
194
+ switch (opType) {
241
195
  case OperationType.Response: {
242
- const callback = this._callbacks.get(requestId);
243
- if (!callback) {
244
- this.logger.error(`Cannot find callback for request ${requestId}`);
245
- return;
246
- }
247
-
248
- this._callbacks.delete(requestId);
249
-
196
+ const method = reader.stringOfVarUInt32();
250
197
  const status = reader.uint16();
251
- // const headers = headerSerializer.read();
252
-
253
- // if error code is not 0, it's an error
254
- if (status === ErrorCode.Err) {
255
- // TODO: use binary codec
256
- assert(codec === BodyCodec.JSON, 'Error response should be JSON encoded');
257
- const content = reader.stringOfVarUInt32();
258
- const error = parseError(content);
259
- callback(nullHeaders, error);
260
- return;
261
- }
262
198
 
263
- if (codec === BodyCodec.Binary) {
264
- const contentLen = reader.varUInt32();
265
- const buffer = reader.buffer(contentLen);
266
- callback(nullHeaders, undefined, buffer);
267
- return;
268
- }
269
-
270
- const content = reader.stringOfVarUInt32();
271
- if (codec === BodyCodec.JSON) {
272
- callback(nullHeaders, undefined, JSON.parse(content));
273
- } else {
274
- callback(nullHeaders, undefined, content);
199
+ const runCallback = (headers: IResponseHeaders, error?: any, result?: any) => {
200
+ const callback = this._callbacks.get(requestId);
201
+ if (!callback) {
202
+ this.logger.error(`Cannot find callback for request ${requestId}`);
203
+ return;
204
+ }
205
+
206
+ this._callbacks.delete(requestId);
207
+
208
+ callback(headers, error, result);
209
+ };
210
+
211
+ const headers = this.io.responseHeadersSerializer.read();
212
+
213
+ switch (status) {
214
+ case Status.Err: {
215
+ // TODO: use binary codec
216
+ const content = reader.stringOfVarUInt32();
217
+ const error = parseError(content);
218
+ runCallback(nullHeaders, error);
219
+ break;
220
+ }
221
+ default: {
222
+ if (headers && headers.chunked) {
223
+ let activeReq: ActiveRequest;
224
+ if (this.activeRequestPool.has(requestId)) {
225
+ activeReq = this.activeRequestPool.get(requestId)!;
226
+ } else {
227
+ activeReq = new ActiveRequest(requestId, headers);
228
+ this.activeRequestPool.set(requestId, activeReq);
229
+ runCallback(headers, undefined, activeReq);
230
+ }
231
+
232
+ const result = this.io.getProcessor(method).readResponse() as Uint8Array;
233
+
234
+ // when result is null, it means the stream is ended.
235
+ if (result) {
236
+ activeReq.emit(result);
237
+ break;
238
+ }
239
+
240
+ activeReq.end();
241
+ this.activeRequestPool.delete(requestId);
242
+ } else {
243
+ const result = this.io.getProcessor(method).readResponse();
244
+ runCallback(headers, undefined, result);
245
+ }
246
+ }
275
247
  }
276
248
  break;
277
249
  }
@@ -279,15 +251,79 @@ export class SumiConnection implements IDisposable {
279
251
  // fall through
280
252
  case OperationType.Request: {
281
253
  const method = reader.stringOfVarUInt32();
282
- const headers = requestHeadersSerializer.read() as IRequestHeaders;
283
-
284
- const contentLen = reader.varUInt32();
285
- const content = reader.buffer(contentLen);
286
- const processor = this.protocolRepository.getProcessor(method);
254
+ const headers = this.io.requestHeadersSerializer.read() as IRequestHeaders;
255
+ const args = this.io.getProcessor(method).readRequest();
256
+
257
+ if (headers.cancelable) {
258
+ const tokenSource = new CancellationTokenSource();
259
+ this._cancellationTokenSources.set(requestId, tokenSource);
260
+ args.push(tokenSource.token);
261
+
262
+ if (this._knownCanceledRequests.has(requestId)) {
263
+ tokenSource.cancel();
264
+ this._knownCanceledRequests.delete(requestId);
265
+ }
266
+ }
287
267
 
288
- const args = processor.deserializeRequest(content);
268
+ switch (opType) {
269
+ case OperationType.Request: {
270
+ let promise: Promise<any>;
271
+
272
+ try {
273
+ let result: any;
274
+
275
+ const handler = this._requestHandlers.get(method);
276
+ if (handler) {
277
+ result = handler(...args);
278
+ } else if (this._starRequestHandler) {
279
+ result = this._starRequestHandler(method, args);
280
+ }
281
+
282
+ promise = Promise.resolve(result);
283
+ } catch (err) {
284
+ promise = Promise.reject(err);
285
+ }
286
+
287
+ const onSuccess = (result: any) => {
288
+ if (isReadableStream(result)) {
289
+ const responseHeaders: IResponseHeaders = {
290
+ chunked: true,
291
+ };
292
+ listenReadable(result, {
293
+ onData: (data) => {
294
+ this.socket.send(this.io.Response(requestId, method, responseHeaders, data));
295
+ },
296
+ onEnd: () => {
297
+ this.socket.send(this.io.Response(requestId, method, responseHeaders, null));
298
+ },
299
+ });
300
+ } else {
301
+ this.socket.send(this.io.Response(requestId, method, nullHeaders, result));
302
+ }
303
+
304
+ this._cancellationTokenSources.delete(requestId);
305
+ };
306
+
307
+ const onError = (err: Error) => {
308
+ this.traceRequestError(method, args, err);
309
+ this.socket.send(this.io.Error(requestId, method, nullHeaders, err));
310
+ this._cancellationTokenSources.delete(requestId);
311
+ };
312
+
313
+ promise.then(onSuccess).catch(onError);
314
+ break;
315
+ }
316
+ case OperationType.Notification: {
317
+ const handler = this._notificationHandlers.get(method);
318
+ if (handler) {
319
+ handler(...args);
320
+ } else if (this._starNotificationHandler) {
321
+ this._starNotificationHandler(method, args);
322
+ }
323
+ break;
324
+ }
325
+ }
289
326
 
290
- this._receiveRequest(rpcType, requestId, method, headers, args);
291
327
  break;
292
328
  }
293
329
  case OperationType.Cancel: {
@@ -313,33 +349,59 @@ export class SumiConnection implements IDisposable {
313
349
  this.disposable.dispose();
314
350
  }
315
351
 
316
- protected _receiveRequest(rpcType: number, requestId: number, method: string, headers: IRequestHeaders, args: any[]) {
317
- const cancelable = headers.cancelable;
318
- if (cancelable) {
319
- const tokenSource = new CancellationTokenSource();
320
- this._cancellationTokenSources.set(requestId, tokenSource);
321
- args.push(tokenSource.token);
352
+ static forWSWebSocket(socket: WebSocket, options: ISumiConnectionOptions = {}) {
353
+ return new SumiConnection(new WSWebSocketConnection(socket), options);
354
+ }
322
355
 
323
- if (this._knownCanceledRequests.has(requestId)) {
324
- tokenSource.cancel();
325
- this._knownCanceledRequests.delete(requestId);
356
+ static forNetSocket(socket: net.Socket, options: ISumiConnectionOptions = {}) {
357
+ return new SumiConnection(new NetSocketConnection(socket), options);
358
+ }
359
+
360
+ private traceRequestError(method: string, args: any[], error: any) {
361
+ this.logger.error(`Error handling request ${method} with args `, args, error);
362
+ }
363
+ }
364
+
365
+ class ActiveRequest implements IReadableStream<Uint8Array> {
366
+ protected dataQ = new EventQueue<Uint8Array>();
367
+ protected endQ = new EventQueue<void>();
368
+
369
+ on(event: 'data', listener: (chunk: Uint8Array) => void): this;
370
+ on(event: 'end', listener: () => void): this;
371
+ on(event: string, listener: (...args: any[]) => void): this;
372
+ on(event: unknown, listener: unknown): this {
373
+ if (typeof event === 'string') {
374
+ switch (event) {
375
+ case 'data':
376
+ this.onData(listener as (chunk: Uint8Array) => void);
377
+ break;
378
+ case 'end':
379
+ this.onEnd(listener as () => void);
380
+ break;
381
+ default:
382
+ break;
326
383
  }
327
384
  }
385
+ return this;
386
+ }
328
387
 
329
- if (rpcType === OperationType.Request) {
330
- const eventName = this._requestEmitter.hasListener(method) ? method : star;
331
- this._requestEmitter.emit(eventName, requestId, method, headers, args);
332
- } else {
333
- const eventName = this._notificationEmitter.hasListener(method) ? method : star;
334
- this._notificationEmitter.emit(eventName, requestId, method, headers, args);
335
- }
388
+ onData(cb: (data: Uint8Array) => void): IDisposable {
389
+ return this.dataQ.on(cb);
336
390
  }
337
391
 
338
- static forWSWebSocket(socket: WebSocket, options: ISumiConnectionOptions = {}) {
339
- return new SumiConnection(new WSWebSocketConnection(socket), options);
392
+ onEnd(cb: () => void): IDisposable {
393
+ return this.endQ.on(cb);
340
394
  }
341
395
 
342
- static forNetSocket(socket: net.Socket, options: ISumiConnectionOptions = {}) {
343
- return new SumiConnection(new NetSocketConnection(socket), options);
396
+ constructor(protected requestId: number, protected responseHeaders: IResponseHeaders) {}
397
+
398
+ emit(buffer: Uint8Array) {
399
+ this.dataQ.push(buffer);
400
+ }
401
+
402
+ end() {
403
+ this.dataQ.dispose();
404
+ this.endQ.push(undefined);
405
+ this.endQ.dispose();
344
406
  }
345
407
  }
@@ -1,2 +1,2 @@
1
1
  export * from './types';
2
- export * from './protocol-repository';
2
+ export * from './message-io';