Skip to content

Commit c5191c3

Browse files
authored
fix: server's incorrect dispose of service center (#3785)
1 parent a84d403 commit c5191c3

15 files changed

Lines changed: 304 additions & 123 deletions

File tree

packages/connection/__test__/browser/index.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ describe('connection browser', () => {
2828
furySerializer.serialize({
2929
id: msgObj.id,
3030
kind: 'server-ready',
31-
token: '',
31+
traceId: '',
3232
}),
3333
);
3434
} else if (msgObj.kind === 'data') {
@@ -66,7 +66,7 @@ describe('connection browser', () => {
6666
channel.dispatch({
6767
kind: 'server-ready',
6868
id: 'test',
69-
token: '',
69+
traceId: '',
7070
});
7171
await sleep(500);
7272
// message queue flushed

packages/connection/__test__/common/fury-extends/one-of.test.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
/* eslint-disable no-console */
2-
3-
import { OpenMessage, PingMessage, PongMessage, ServerReadyMessage, furySerializer } from '@opensumi/ide-connection';
1+
import { OpenMessage, PingMessage, PongMessage, ServerReadyMessage } from '../../../src/common/channel/types';
2+
import { furySerializer } from '../../../src/common/serializer';
43

54
const parse = furySerializer.deserialize;
65
const stringify = furySerializer.serialize;
@@ -9,11 +8,12 @@ describe('oneOf', () => {
98
function testIt(obj: any) {
109
const bytes = stringify(obj);
1110
const obj2 = parse(bytes);
12-
expect(obj2).toEqual(obj);
13-
const str = JSON.stringify(obj);
1411

15-
console.log('bytes.length', bytes.byteLength);
16-
console.log('json length', str.length);
12+
// 确保 obj 里的所有字段都在 obj2 里
13+
// eslint-disable-next-line guard-for-in
14+
for (const key in Object.keys(obj)) {
15+
expect(obj2[key]).toEqual(obj[key]);
16+
}
1717
}
1818

1919
it('should serialize and deserialize', () => {
@@ -36,15 +36,15 @@ describe('oneOf', () => {
3636
clientId: '123',
3737
id: '456',
3838
path: '/test',
39-
connectionToken: 'abc',
39+
traceId: '12312312',
4040
};
4141

4242
testIt(obj3);
4343

4444
const obj4: ServerReadyMessage = {
4545
kind: 'server-ready',
4646
id: '456',
47-
token: '',
47+
traceId: '123123',
4848
};
4949

5050
testIt(obj4);

packages/connection/src/common/channel/types.ts

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,41 +8,42 @@ export type ChannelMessage =
88
| CloseMessage
99
| ErrorMessage;
1010

11+
export interface BaseMessage {
12+
kind: string;
13+
id: string;
14+
traceId?: string;
15+
}
16+
1117
/**
1218
* `ping` and `pong` are used to detect whether the connection is alive.
1319
*/
14-
export interface PingMessage {
20+
export interface PingMessage extends BaseMessage {
1521
kind: 'ping';
16-
id: string;
1722
}
1823

1924
/**
2025
* when server receive a `ping` message, it should reply a `pong` message, vice versa.
2126
*/
22-
export interface PongMessage {
27+
export interface PongMessage extends BaseMessage {
2328
kind: 'pong';
24-
id: string;
2529
}
2630

2731
/**
2832
* `data` message indicate that the channel has received some data.
2933
* the `content` field is the data, it should be a string.
3034
*/
31-
export interface DataMessage {
35+
export interface DataMessage extends BaseMessage {
3236
kind: 'data';
33-
id: string;
3437
content: string;
3538
}
3639

37-
export interface BinaryMessage {
40+
export interface BinaryMessage extends BaseMessage {
3841
kind: 'binary';
39-
id: string;
4042
binary: Uint8Array;
4143
}
4244

43-
export interface CloseMessage {
45+
export interface CloseMessage extends BaseMessage {
4446
kind: 'close';
45-
id: string;
4647
code: number;
4748
reason: string;
4849
}
@@ -52,19 +53,18 @@ export interface CloseMessage {
5253
* `path` is used to identify which handler should be used to handle the channel.
5354
* `clientId` is used to identify the client.
5455
*/
55-
export interface OpenMessage {
56+
export interface OpenMessage extends BaseMessage {
5657
kind: 'open';
57-
id: string;
5858
path: string;
5959
clientId: string;
60-
connectionToken: string;
60+
traceId: string;
6161
}
6262

6363
export enum ErrorMessageCode {
6464
ChannelNotFound = 1,
6565
}
6666

67-
export interface ErrorMessage {
67+
export interface ErrorMessage extends BaseMessage {
6868
kind: 'error';
6969
id: string;
7070
code: ErrorMessageCode;
@@ -75,8 +75,8 @@ export interface ErrorMessage {
7575
* when server receive a `open` message, it should reply a `server-ready` message.
7676
* this is indicate that the channel is ready to use.
7777
*/
78-
export interface ServerReadyMessage {
78+
export interface ServerReadyMessage extends BaseMessage {
7979
kind: 'server-ready';
8080
id: string;
81-
token: string;
81+
traceId: string;
8282
}

packages/connection/src/common/rpc-service/center.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,8 @@ export class RPCServiceCenter implements IDisposable {
177177

178178
dispose(): void {
179179
this._disposables.dispose();
180+
this.proxies.forEach((proxy) => proxy.dispose());
181+
this.proxies = [];
180182
}
181183
}
182184

packages/connection/src/common/serializer/fury.ts

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,44 +5,50 @@ import { oneOf } from '../fury-extends/one-of';
55

66
import { ISerializer } from './types';
77

8+
function baseFields() {
9+
return {
10+
id: Type.string(),
11+
};
12+
}
13+
814
export const PingProtocol = Type.object('ping', {
9-
id: Type.string(),
15+
...baseFields(),
1016
});
1117

1218
export const PongProtocol = Type.object('pong', {
13-
id: Type.string(),
19+
...baseFields(),
1420
});
1521

1622
export const OpenProtocol = Type.object('open', {
23+
...baseFields(),
1724
clientId: Type.string(),
18-
id: Type.string(),
1925
path: Type.string(),
20-
connectionToken: Type.string(),
26+
traceId: Type.string(),
2127
});
2228

2329
export const ServerReadyProtocol = Type.object('server-ready', {
24-
id: Type.string(),
25-
token: Type.string(),
30+
...baseFields(),
31+
traceId: Type.string(),
2632
});
2733

2834
export const ErrorProtocol = Type.object('error', {
29-
id: Type.string(),
35+
...baseFields(),
3036
code: Type.uint16(),
3137
message: Type.string(),
3238
});
3339

3440
export const DataProtocol = Type.object('data', {
35-
id: Type.string(),
41+
...baseFields(),
3642
content: Type.string(),
3743
});
3844

3945
export const BinaryProtocol = Type.object('binary', {
40-
id: Type.string(),
46+
...baseFields(),
4147
binary: Type.binary(),
4248
});
4349

4450
export const CloseProtocol = Type.object('close', {
45-
id: Type.string(),
51+
...baseFields(),
4652
code: Type.uint32(),
4753
reason: Type.string(),
4854
});

packages/connection/src/common/server-handler.ts

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@ export interface ChannelHandlerOptions {
104104
serializer?: ISerializer<ChannelMessage, any>;
105105
}
106106

107+
enum ServerChannelCloseCode {
108+
ConnectionClosed = 1,
109+
NewChannelOpened = 2,
110+
}
111+
107112
export abstract class BaseCommonChannelHandler {
108113
protected channelMap: Map<string, WSServerChannel> = new Map();
109114

@@ -135,25 +140,24 @@ export abstract class BaseCommonChannelHandler {
135140

136141
const wrappedConnection = wrapSerializer(connection, this.serializer);
137142

138-
const getOrCreateChannel = (id: string, clientId: string) => {
139-
let channel = this.channelMap.get(id);
140-
if (!channel) {
141-
channel = new WSServerChannel(wrappedConnection, { id, clientId, logger: this.logger });
142-
this.channelMap.set(id, channel);
143-
}
144-
return channel;
145-
};
146-
147143
wrappedConnection.onMessage((msg: ChannelMessage) => {
148144
try {
149145
switch (msg.kind) {
150146
case 'open': {
151-
const { id, path, connectionToken } = msg;
147+
const { id, path, traceId } = msg;
152148
clientId = msg.clientId;
149+
153150
this.logger.log(`open a new connection channel ${clientId} with path ${path}`);
154-
const channel = getOrCreateChannel(id, clientId);
151+
let channel = this.channelMap.get(id);
152+
if (channel) {
153+
channel.close(ServerChannelCloseCode.NewChannelOpened, 'new channel opened for the same channel id');
154+
channel.dispose();
155+
}
156+
157+
channel = new WSServerChannel(wrappedConnection, { id, clientId, logger: this.logger });
158+
this.channelMap.set(id, channel);
155159
commonChannelPathHandler.openChannel(path, channel, clientId);
156-
channel.serverReady(connectionToken);
160+
channel.serverReady(traceId);
157161
break;
158162
}
159163
default: {
@@ -186,7 +190,7 @@ export abstract class BaseCommonChannelHandler {
186190
Array.from(this.channelMap.values())
187191
.filter((channel) => channel.clientId === clientId)
188192
.forEach((channel) => {
189-
channel.close(1, 'close');
193+
channel.close(ServerChannelCloseCode.ConnectionClosed, 'connection closed');
190194
channel.dispose();
191195
this.channelMap.delete(channel.id);
192196
this.logger.log(`Remove connection channel ${channel.id}`);

0 commit comments

Comments
 (0)