Skip to content

Commit 78749d8

Browse files
committed
feat: support one of
1 parent 315dbd6 commit 78749d8

3 files changed

Lines changed: 223 additions & 31 deletions

File tree

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/* eslint-disable no-console */
2+
import { Type } from '@furyjs/fury';
3+
4+
import { oneOf } from '@opensumi/ide-connection/src/common/fury-extends/one-of';
5+
6+
import { PongMessage } from '../../../lib';
7+
import { ChannelMessage, PingMessage } from '../../../src/common/ws-channel';
8+
9+
export const PingProtocol = Type.object('ping', {
10+
clientId: Type.string(),
11+
id: Type.string(),
12+
});
13+
14+
export const PongProtocol = Type.object('pong', {
15+
clientId: Type.string(),
16+
id: Type.string(),
17+
});
18+
19+
export const OpenProtocol = Type.object('open', {
20+
clientId: Type.string(),
21+
id: Type.string(),
22+
path: Type.string(),
23+
});
24+
25+
export const ServerReadyProtocol = Type.object('server-ready', {
26+
id: Type.string(),
27+
});
28+
29+
export const DataProtocol = Type.object('data', {
30+
id: Type.string(),
31+
content: Type.string(),
32+
});
33+
34+
export const BinaryProtocol = Type.object('binary', {
35+
id: Type.string(),
36+
binary: Type.binary(),
37+
});
38+
39+
export const CloseProtocol = Type.object('close', {
40+
id: Type.string(),
41+
code: Type.uint32(),
42+
reason: Type.string(),
43+
});
44+
45+
const serializer = oneOf([
46+
PingProtocol,
47+
PongProtocol,
48+
OpenProtocol,
49+
ServerReadyProtocol,
50+
DataProtocol,
51+
BinaryProtocol,
52+
CloseProtocol,
53+
]);
54+
55+
function stringify(obj: ChannelMessage): Uint8Array {
56+
return serializer.serialize(obj);
57+
}
58+
59+
function parse(input: Uint8Array): ChannelMessage {
60+
return serializer.deserialize(input) as any;
61+
}
62+
63+
describe('oneOf', () => {
64+
function testIt(obj: any) {
65+
const bytes = stringify(obj);
66+
const obj2 = parse(bytes);
67+
expect(obj2).toEqual(obj);
68+
const str = JSON.stringify(obj);
69+
70+
console.log('bytes.length', bytes.byteLength);
71+
console.log('json length', str.length);
72+
}
73+
74+
it('should serialize and deserialize', () => {
75+
const obj = {
76+
kind: 'ping',
77+
clientId: '123',
78+
id: '456',
79+
} as PingMessage;
80+
81+
testIt(obj);
82+
83+
const obj2 = {
84+
kind: 'pong',
85+
clientId: '123',
86+
id: '456',
87+
} as PongMessage;
88+
89+
testIt(obj2);
90+
91+
const obj3 = {
92+
kind: 'open',
93+
clientId: '123',
94+
id: '456',
95+
path: '/test',
96+
};
97+
98+
testIt(obj3);
99+
100+
const obj4 = {
101+
kind: 'server-ready',
102+
id: '456',
103+
};
104+
105+
testIt(obj4);
106+
107+
const obj5 = {
108+
kind: 'data',
109+
id: '456',
110+
content: 'hello',
111+
};
112+
113+
testIt(obj5);
114+
115+
const obj6 = {
116+
kind: 'binary',
117+
id: '456',
118+
binary: Buffer.from([1, 2, 3]),
119+
};
120+
testIt(obj6);
121+
});
122+
});
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { ObjectTypeDescription, Serializer, TypeDescription } from '@furyjs/fury';
2+
import Fury from '@furyjs/fury/dist/lib/fury';
3+
import { generateSerializer } from '@furyjs/fury/dist/lib/gen';
4+
5+
type Writable = Record<string, any> & { kind: string };
6+
7+
const fury = Fury({});
8+
const reader = fury.binaryReader;
9+
const writer = fury.binaryWriter;
10+
11+
export const oneOf = (schemas: TypeDescription[]) => {
12+
const registry = new Map<string, Serializer>();
13+
14+
schemas.forEach((schema) => {
15+
registry.set((schema as ObjectTypeDescription).options.tag, generateSerializer(fury, schema));
16+
});
17+
18+
const deserialize = (bytes: Uint8Array) => {
19+
reader.reset(bytes);
20+
const kind = reader.stringOfVarUInt32();
21+
const serializer = registry.get(kind);
22+
if (!serializer) {
23+
throw new Error(`Unknown kind: ${kind}`);
24+
}
25+
26+
const v = serializer.read();
27+
v.kind = kind;
28+
29+
return v;
30+
};
31+
32+
const serializeVolatile = (v: Writable) => {
33+
const serializer = registry.get(v.kind);
34+
if (!serializer) {
35+
throw new Error(`Unknown kind: ${v.kind}`);
36+
}
37+
38+
writer.reset();
39+
writer.stringOfVarUInt32(v.kind);
40+
serializer.write(v);
41+
42+
return writer.dumpAndOwn();
43+
};
44+
45+
const serialize = (v: Writable) => {
46+
const serializer = registry.get(v.kind);
47+
if (!serializer) {
48+
throw new Error(`Unknown kind: ${v.kind}`);
49+
}
50+
51+
writer.reset();
52+
writer.stringOfVarUInt32(v.kind);
53+
serializer.write(v);
54+
55+
return writer.dump();
56+
};
57+
58+
return {
59+
deserialize,
60+
serialize,
61+
serializeVolatile,
62+
};
63+
};

packages/connection/src/common/ws-channel.ts

Lines changed: 38 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import type net from 'net';
22

3-
import Fury, { Type } from '@furyjs/fury';
3+
import { Type } from '@furyjs/fury';
44
import type WebSocket from 'ws';
55

66
import { EventEmitter } from '@opensumi/events';
77
import { DisposableCollection } from '@opensumi/ide-core-common';
88

99
import { NetSocketConnection, WSWebSocketConnection } from './connection';
1010
import { IConnectionShape } from './connection/types';
11+
import { oneOf } from './fury-extends/one-of';
1112
import { createWebSocketConnection } from './message';
1213
import { Connection } from './rpc/connection';
1314
import { ILogger } from './types';
@@ -287,50 +288,56 @@ export class WSChannel implements IWebSocket {
287288
}
288289
}
289290

290-
export type MessageString = string & {
291-
origin?: any;
292-
};
293-
294-
/**
295-
* 路径信息 ${pre}-${index}
296-
*/
297-
export class ChildConnectPath {
298-
public pathPre = 'child_connect-';
299-
300-
getConnectPath(index: number, clientId: string) {
301-
return `${this.pathPre}${index + 1}`;
302-
}
303-
304-
parseInfo(pathString: string) {
305-
const list = pathString.split('-');
306-
307-
return {
308-
pre: list[0],
309-
index: list[1],
310-
clientId: list[2],
311-
};
312-
}
313-
}
291+
export const PingProtocol = Type.object('ping', {
292+
clientId: Type.string(),
293+
id: Type.string(),
294+
});
314295

315-
const fury = new Fury({});
296+
export const PongProtocol = Type.object('pong', {
297+
clientId: Type.string(),
298+
id: Type.string(),
299+
});
316300

317-
export const wsChannelProtocol = Type.object('ws-channel-protocol', {
318-
kind: Type.string(),
301+
export const OpenProtocol = Type.object('open', {
319302
clientId: Type.string(),
320303
id: Type.string(),
321304
path: Type.string(),
305+
});
306+
307+
export const ServerReadyProtocol = Type.object('server-ready', {
308+
id: Type.string(),
309+
});
310+
311+
export const DataProtocol = Type.object('data', {
312+
id: Type.string(),
322313
content: Type.string(),
314+
});
315+
316+
export const BinaryProtocol = Type.object('binary', {
317+
id: Type.string(),
323318
binary: Type.binary(),
319+
});
320+
321+
export const CloseProtocol = Type.object('close', {
322+
id: Type.string(),
324323
code: Type.uint32(),
325324
reason: Type.string(),
326325
});
327326

328-
const wsChannelProtocolSerializer = fury.registerSerializer(wsChannelProtocol);
327+
const serializer = oneOf([
328+
PingProtocol,
329+
PongProtocol,
330+
OpenProtocol,
331+
ServerReadyProtocol,
332+
DataProtocol,
333+
BinaryProtocol,
334+
CloseProtocol,
335+
]);
329336

330337
export function stringify(obj: ChannelMessage): Uint8Array {
331-
return wsChannelProtocolSerializer.serialize(obj);
338+
return serializer.serialize(obj);
332339
}
333340

334341
export function parse(input: Uint8Array): ChannelMessage {
335-
return wsChannelProtocolSerializer.deserialize(input) as any;
342+
return serializer.deserialize(input) as any;
336343
}

0 commit comments

Comments
 (0)