@opensumi/ide-connection 3.1.2-next-1718701452.0 → 3.1.2-next-1718769324.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/common/channel/types.d.ts +15 -16
- package/lib/common/channel/types.d.ts.map +1 -1
- package/lib/common/rpc/message-io.d.ts +0 -5
- package/lib/common/rpc/message-io.d.ts.map +1 -1
- package/lib/common/rpc/message-io.js +0 -5
- package/lib/common/rpc/message-io.js.map +1 -1
- package/lib/common/rpc-service/center.d.ts.map +1 -1
- package/lib/common/rpc-service/center.js +2 -0
- package/lib/common/rpc-service/center.js.map +1 -1
- package/lib/common/serializer/fury.d.ts +16 -16
- package/lib/common/serializer/fury.d.ts.map +1 -1
- package/lib/common/serializer/fury.js +13 -34
- package/lib/common/serializer/fury.js.map +1 -1
- package/lib/common/server-handler.d.ts.map +1 -1
- package/lib/common/server-handler.js +15 -12
- package/lib/common/server-handler.js.map +1 -1
- package/lib/common/ws-channel.d.ts +32 -12
- package/lib/common/ws-channel.d.ts.map +1 -1
- package/lib/common/ws-channel.js +93 -38
- package/lib/common/ws-channel.js.map +1 -1
- package/package.json +5 -5
- package/src/common/channel/types.ts +16 -16
- package/src/common/rpc/message-io.ts +0 -5
- package/src/common/rpc-service/center.ts +2 -0
- package/src/common/serializer/fury.ts +16 -10
- package/src/common/server-handler.ts +17 -13
- package/src/common/ws-channel.ts +119 -48
package/src/common/ws-channel.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EventEmitter } from '@opensumi/events';
|
|
2
|
-
import { DisposableStore, EventQueue,
|
|
2
|
+
import { DisposableStore, EventQueue, randomString } from '@opensumi/ide-core-common';
|
|
3
3
|
|
|
4
4
|
import { ChannelMessage, ErrorMessageCode } from './channel/types';
|
|
5
5
|
import { IConnectionShape } from './connection/types';
|
|
@@ -15,6 +15,82 @@ export interface IWSChannelCreateOptions {
|
|
|
15
15
|
logger?: ILogger;
|
|
16
16
|
|
|
17
17
|
ensureServerReady?: boolean;
|
|
18
|
+
deliveryTimeout?: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
enum MessageDeliveryState {
|
|
22
|
+
ReSend,
|
|
23
|
+
Sended,
|
|
24
|
+
Success,
|
|
25
|
+
Failed,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
class StateTracer {
|
|
29
|
+
private map = new Map<string, MessageDeliveryState>();
|
|
30
|
+
|
|
31
|
+
protected deliveryTimeout = 500;
|
|
32
|
+
protected timerMap = new Map<string, NodeJS.Timeout>();
|
|
33
|
+
|
|
34
|
+
setDeliveryTimeout(timeout: number) {
|
|
35
|
+
this.deliveryTimeout = timeout;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
protected set(traceId: string, state: MessageDeliveryState) {
|
|
39
|
+
this.map.set(traceId, state);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
get(traceId: string) {
|
|
43
|
+
return this.map.get(traceId);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
success(traceId: string) {
|
|
47
|
+
this.map.set(traceId, MessageDeliveryState.Success);
|
|
48
|
+
const timer = this.timerMap.get(traceId);
|
|
49
|
+
if (timer) {
|
|
50
|
+
clearTimeout(timer);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
dispose() {
|
|
55
|
+
this.timerMap.forEach((timer) => {
|
|
56
|
+
clearTimeout(timer);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
stop(traceId: string) {
|
|
61
|
+
const timer = this.timerMap.get(traceId);
|
|
62
|
+
if (timer) {
|
|
63
|
+
clearTimeout(timer);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
send(
|
|
68
|
+
traceId: string,
|
|
69
|
+
options: {
|
|
70
|
+
whenRetry: () => void;
|
|
71
|
+
},
|
|
72
|
+
) {
|
|
73
|
+
this.set(traceId, MessageDeliveryState.Sended);
|
|
74
|
+
this.guard(traceId, options);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
guard(
|
|
78
|
+
traceId: string,
|
|
79
|
+
options: {
|
|
80
|
+
whenRetry: () => void;
|
|
81
|
+
},
|
|
82
|
+
) {
|
|
83
|
+
const timer = this.timerMap.get(traceId);
|
|
84
|
+
if (timer) {
|
|
85
|
+
clearTimeout(timer);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const newTimer = setTimeout(() => {
|
|
89
|
+
this.set(traceId, MessageDeliveryState.ReSend);
|
|
90
|
+
options.whenRetry();
|
|
91
|
+
}, this.deliveryTimeout);
|
|
92
|
+
this.timerMap.set(traceId, newTimer);
|
|
93
|
+
}
|
|
18
94
|
}
|
|
19
95
|
|
|
20
96
|
export class WSChannel {
|
|
@@ -35,6 +111,8 @@ export class WSChannel {
|
|
|
35
111
|
protected _isServerReady = false;
|
|
36
112
|
protected _ensureServerReady: boolean | undefined;
|
|
37
113
|
|
|
114
|
+
protected stateTracer = new StateTracer();
|
|
115
|
+
|
|
38
116
|
public id: string;
|
|
39
117
|
|
|
40
118
|
public channelPath: string;
|
|
@@ -53,6 +131,9 @@ export class WSChannel {
|
|
|
53
131
|
}
|
|
54
132
|
|
|
55
133
|
this._ensureServerReady = Boolean(ensureServerReady);
|
|
134
|
+
if (options.deliveryTimeout) {
|
|
135
|
+
this.stateTracer.setDeliveryTimeout(options.deliveryTimeout);
|
|
136
|
+
}
|
|
56
137
|
|
|
57
138
|
this._disposables.add(this.emitter.on('binary', (data) => this.onBinaryQueue.push(data)));
|
|
58
139
|
}
|
|
@@ -68,6 +149,30 @@ export class WSChannel {
|
|
|
68
149
|
this.connection.send(data);
|
|
69
150
|
}
|
|
70
151
|
|
|
152
|
+
/**
|
|
153
|
+
* @param traceId 一个 connection token 用于在全链路中追踪一个消息的生命周期,防止消息未发送或者重复发送
|
|
154
|
+
*/
|
|
155
|
+
protected ensureMessageDeliveried(data: ChannelMessage, traceId = randomString(16)) {
|
|
156
|
+
const state = this.stateTracer.get(traceId);
|
|
157
|
+
if (state && state >= MessageDeliveryState.Sended) {
|
|
158
|
+
this.logger.error(`message already send already success or in progress, traceId: ${traceId}, state: ${state}`);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
data.traceId = traceId;
|
|
163
|
+
this.connection.send(data);
|
|
164
|
+
|
|
165
|
+
this.stateTracer.send(traceId, {
|
|
166
|
+
whenRetry: () => {
|
|
167
|
+
if (this._isServerReady) {
|
|
168
|
+
this.stateTracer.stop(traceId);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
this.ensureMessageDeliveried(data, traceId);
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
71
176
|
onMessage(cb: (data: string) => any) {
|
|
72
177
|
return this.emitter.on('message', cb);
|
|
73
178
|
}
|
|
@@ -106,11 +211,11 @@ export class WSChannel {
|
|
|
106
211
|
dispatch(msg: ChannelMessage) {
|
|
107
212
|
switch (msg.kind) {
|
|
108
213
|
case 'server-ready':
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
if (this.timer) {
|
|
112
|
-
clearTimeout(this.timer);
|
|
214
|
+
if (msg.traceId) {
|
|
215
|
+
this.stateTracer.success(msg.traceId);
|
|
113
216
|
}
|
|
217
|
+
|
|
218
|
+
this.resume();
|
|
114
219
|
this.emitter.emit('open', msg.id);
|
|
115
220
|
break;
|
|
116
221
|
case 'data':
|
|
@@ -136,56 +241,24 @@ export class WSChannel {
|
|
|
136
241
|
}
|
|
137
242
|
}
|
|
138
243
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* @param connectionToken 一个 connection token 用于在全链路中追踪一个 channel 的生命周期,防止 channel 被重复打开
|
|
143
|
-
*/
|
|
144
|
-
open(path: string, clientId: string, connectionToken = randomString(16)) {
|
|
244
|
+
open(path: string, clientId: string) {
|
|
145
245
|
this.channelPath = path;
|
|
146
246
|
this.clientId = clientId;
|
|
147
247
|
|
|
148
248
|
this.LOG_TAG = `[WSChannel id=${this.id} path=${path}]`;
|
|
149
249
|
|
|
150
|
-
|
|
151
|
-
this.logger.warn(
|
|
152
|
-
`channel already opened or in progress, path: ${path}, clientId: ${clientId}, connectionToken: ${connectionToken}`,
|
|
153
|
-
);
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
this.stateTracer.record(connectionToken);
|
|
158
|
-
|
|
159
|
-
this.connection.send({
|
|
250
|
+
const msg = {
|
|
160
251
|
kind: 'open',
|
|
161
252
|
id: this.id,
|
|
162
253
|
path,
|
|
163
254
|
clientId,
|
|
164
|
-
|
|
165
|
-
});
|
|
255
|
+
} as ChannelMessage;
|
|
166
256
|
|
|
167
257
|
if (this._ensureServerReady) {
|
|
168
|
-
this.
|
|
258
|
+
this.ensureMessageDeliveried(msg);
|
|
259
|
+
} else {
|
|
260
|
+
this.connection.send(msg);
|
|
169
261
|
}
|
|
170
|
-
|
|
171
|
-
return connectionToken;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
protected timer: NodeJS.Timeout;
|
|
175
|
-
/**
|
|
176
|
-
* 启动定时器,确保 server-ready 消息在一定时间内到达
|
|
177
|
-
*/
|
|
178
|
-
protected ensureOpenSend(path: string, clientId: string, connectionToken: string) {
|
|
179
|
-
if (this.timer) {
|
|
180
|
-
clearTimeout(this.timer);
|
|
181
|
-
}
|
|
182
|
-
this.timer = setTimeout(() => {
|
|
183
|
-
if (this._isServerReady) {
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
this.stateTracer.delete(connectionToken);
|
|
187
|
-
this.open(path, clientId, connectionToken);
|
|
188
|
-
}, 500);
|
|
189
262
|
}
|
|
190
263
|
|
|
191
264
|
send(content: string) {
|
|
@@ -235,9 +308,7 @@ export class WSChannel {
|
|
|
235
308
|
}
|
|
236
309
|
|
|
237
310
|
dispose() {
|
|
238
|
-
|
|
239
|
-
clearTimeout(this.timer);
|
|
240
|
-
}
|
|
311
|
+
this.stateTracer.dispose();
|
|
241
312
|
this.sendQueue = [];
|
|
242
313
|
this._disposables.dispose();
|
|
243
314
|
}
|
|
@@ -266,11 +337,11 @@ export class WSServerChannel extends WSChannel {
|
|
|
266
337
|
this.clientId = options.clientId;
|
|
267
338
|
}
|
|
268
339
|
|
|
269
|
-
serverReady(
|
|
340
|
+
serverReady(traceId: string) {
|
|
270
341
|
this.connection.send({
|
|
271
342
|
kind: 'server-ready',
|
|
272
343
|
id: this.id,
|
|
273
|
-
|
|
344
|
+
traceId,
|
|
274
345
|
});
|
|
275
346
|
}
|
|
276
347
|
|