@dxos/edge-client 0.6.12-main.ed7cda7 → 0.6.12-staging.0b4bb48
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/dist/lib/browser/index.mjs +157 -57
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +154 -56
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/types/src/defs.d.ts.map +1 -1
- package/dist/types/src/edge-client.d.ts +2 -3
- package/dist/types/src/edge-client.d.ts.map +1 -1
- package/dist/types/src/errors.d.ts +1 -4
- package/dist/types/src/errors.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +0 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/protocol.d.ts +2 -2
- package/dist/types/src/protocol.d.ts.map +1 -1
- package/dist/types/src/test-utils.d.ts +11 -0
- package/dist/types/src/test-utils.d.ts.map +1 -0
- package/package.json +14 -26
- package/src/defs.ts +3 -2
- package/src/edge-client.test.ts +11 -11
- package/src/edge-client.ts +8 -17
- package/src/errors.ts +2 -8
- package/src/index.ts +0 -1
- package/src/persistent-lifecycle.test.ts +2 -2
- package/src/protocol.test.ts +2 -1
- package/src/protocol.ts +2 -2
- package/src/test-utils.ts +49 -0
- package/src/websocket.test.ts +4 -5
- package/dist/lib/browser/chunk-ZWJXA37R.mjs +0 -113
- package/dist/lib/browser/chunk-ZWJXA37R.mjs.map +0 -7
- package/dist/lib/browser/testing/index.mjs +0 -122
- package/dist/lib/browser/testing/index.mjs.map +0 -7
- package/dist/lib/node/chunk-ANV2HBEH.cjs +0 -136
- package/dist/lib/node/chunk-ANV2HBEH.cjs.map +0 -7
- package/dist/lib/node/testing/index.cjs +0 -152
- package/dist/lib/node/testing/index.cjs.map +0 -7
- package/dist/lib/node-esm/chunk-HNVT57AU.mjs +0 -115
- package/dist/lib/node-esm/chunk-HNVT57AU.mjs.map +0 -7
- package/dist/lib/node-esm/index.mjs +0 -378
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/lib/node-esm/testing/index.mjs +0 -123
- package/dist/lib/node-esm/testing/index.mjs.map +0 -7
- package/dist/types/src/testing/index.d.ts +0 -2
- package/dist/types/src/testing/index.d.ts.map +0 -1
- package/dist/types/src/testing/test-utils.d.ts +0 -20
- package/dist/types/src/testing/test-utils.d.ts.map +0 -1
- package/src/testing/index.ts +0 -5
- package/src/testing/test-utils.ts +0 -111
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../../src/protocol.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,GAAG,EAAU,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,KAAK,OAAO,EAAiB,KAAK,
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../../src/protocol.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,GAAG,EAAU,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,KAAK,OAAO,EAAiB,KAAK,IAAI,IAAI,SAAS,EAAE,MAAM,4CAA4C,CAAC;AAGjH,MAAM,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;AAE1C,eAAO,MAAM,WAAW,aAAc,MAAM,WAAsC,CAAC;AAEnF;;GAEG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAe;gBAEjC,KAAK,EAAE,GAAG,CAAC,WAAW,EAAE;IAIpC,IAAI,YAAY,IAAI,GAAG,CAAC,QAAQ,CAE/B;IAED,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,GAAG;IAQ7B;;OAEG;IACH,UAAU,CAAC,IAAI,SAAS,GAAG,CAAC,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC;IAa9F;;OAEG;IACH,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS;IASpD;;OAEG;IACH,aAAa,CAAC,IAAI,SAAS,GAAG,CAAC,WAAW,EACxC,IAAI,EAAE,IAAI,EACV,EACE,MAAM,EACN,MAAM,EACN,OAAO,EACP,SAAS,GACV,EAAE;QACD,MAAM,CAAC,EAAE,QAAQ,CAAC;QAClB,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC;QACpB,OAAO,CAAC,EAAE,GAAG,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACrC,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB;CAUJ;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,SAAgB,GAAG,KAAG,OAAO,CAAC,UAAU,CAYhE,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import WebSocket from 'isomorphic-ws';
|
|
2
|
+
export declare const DEFAULT_PORT = 8080;
|
|
3
|
+
export declare const createTestWsServer: (port?: number) => Promise<{
|
|
4
|
+
server: WebSocket.Server;
|
|
5
|
+
/**
|
|
6
|
+
* Close the server connection.
|
|
7
|
+
*/
|
|
8
|
+
error: () => Promise<void>;
|
|
9
|
+
endpoint: string;
|
|
10
|
+
}>;
|
|
11
|
+
//# sourceMappingURL=test-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-utils.d.ts","sourceRoot":"","sources":["../../../src/test-utils.ts"],"names":[],"mappings":"AAIA,OAAO,SAAS,MAAM,eAAe,CAAC;AAWtC,eAAO,MAAM,YAAY,OAAO,CAAC;AAEjC,eAAO,MAAM,kBAAkB;;IAsB3B;;OAEG;;;EAON,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/edge-client",
|
|
3
|
-
"version": "0.6.12-
|
|
3
|
+
"version": "0.6.12-staging.0b4bb48",
|
|
4
4
|
"description": "EDGE Client",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -10,27 +10,14 @@
|
|
|
10
10
|
".": {
|
|
11
11
|
"browser": "./dist/lib/browser/index.mjs",
|
|
12
12
|
"node": {
|
|
13
|
-
"
|
|
14
|
-
"default": "./dist/lib/node-esm/index.mjs"
|
|
13
|
+
"default": "./dist/lib/node/index.cjs"
|
|
15
14
|
},
|
|
16
15
|
"types": "./dist/types/src/index.d.ts"
|
|
17
|
-
},
|
|
18
|
-
"./testing": {
|
|
19
|
-
"browser": "./dist/lib/browser/testing/index.mjs",
|
|
20
|
-
"node": {
|
|
21
|
-
"require": "./dist/lib/node/testing/index.cjs",
|
|
22
|
-
"default": "./dist/lib/node-esm/testing/index.mjs"
|
|
23
|
-
},
|
|
24
|
-
"types": "./dist/types/src/testing/index.d.ts"
|
|
25
16
|
}
|
|
26
17
|
},
|
|
27
18
|
"types": "dist/types/src/index.d.ts",
|
|
28
19
|
"typesVersions": {
|
|
29
|
-
"*": {
|
|
30
|
-
"testing": [
|
|
31
|
-
"dist/types/src/testing/index.d.ts"
|
|
32
|
-
]
|
|
33
|
-
}
|
|
20
|
+
"*": {}
|
|
34
21
|
},
|
|
35
22
|
"files": [
|
|
36
23
|
"dist",
|
|
@@ -38,20 +25,21 @@
|
|
|
38
25
|
"README.md"
|
|
39
26
|
],
|
|
40
27
|
"dependencies": {
|
|
28
|
+
"@bufbuild/protobuf": "^2.0.0",
|
|
41
29
|
"isomorphic-ws": "^5.0.0",
|
|
42
30
|
"ws": "^8.14.2",
|
|
43
|
-
"@dxos/async": "0.6.12-
|
|
44
|
-
"@dxos/context": "0.6.12-
|
|
45
|
-
"@dxos/
|
|
46
|
-
"@dxos/
|
|
47
|
-
"@dxos/
|
|
48
|
-
"@dxos/
|
|
49
|
-
"@dxos/protocols": "0.6.12-
|
|
50
|
-
"@dxos/
|
|
31
|
+
"@dxos/async": "0.6.12-staging.0b4bb48",
|
|
32
|
+
"@dxos/context": "0.6.12-staging.0b4bb48",
|
|
33
|
+
"@dxos/invariant": "0.6.12-staging.0b4bb48",
|
|
34
|
+
"@dxos/debug": "0.6.12-staging.0b4bb48",
|
|
35
|
+
"@dxos/node-std": "0.6.12-staging.0b4bb48",
|
|
36
|
+
"@dxos/util": "0.6.12-staging.0b4bb48",
|
|
37
|
+
"@dxos/protocols": "0.6.12-staging.0b4bb48",
|
|
38
|
+
"@dxos/log": "0.6.12-staging.0b4bb48"
|
|
51
39
|
},
|
|
52
40
|
"devDependencies": {
|
|
53
|
-
"
|
|
54
|
-
"@dxos/
|
|
41
|
+
"jest-websocket-mock": "^2.5.0",
|
|
42
|
+
"@dxos/keys": "0.6.12-staging.0b4bb48"
|
|
55
43
|
},
|
|
56
44
|
"publishConfig": {
|
|
57
45
|
"access": "public"
|
package/src/defs.ts
CHANGED
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { AnySchema } from '@bufbuild/protobuf/wkt';
|
|
6
|
+
|
|
6
7
|
import { SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema } from '@dxos/protocols/buf/dxos/edge/messenger_pb';
|
|
7
8
|
|
|
8
9
|
import { Protocol } from './protocol';
|
|
9
10
|
|
|
10
|
-
export const protocol = new Protocol([SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema,
|
|
11
|
+
export const protocol = new Protocol([SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema, AnySchema]);
|
package/src/edge-client.test.ts
CHANGED
|
@@ -2,23 +2,24 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import chai, { expect } from 'chai';
|
|
6
|
+
import chaiAsPromised from 'chai-as-promised';
|
|
6
7
|
|
|
7
8
|
import { PublicKey } from '@dxos/keys';
|
|
8
9
|
import { TextMessageSchema } from '@dxos/protocols/buf/dxos/edge/messenger_pb';
|
|
9
|
-
import { openAndClose } from '@dxos/test
|
|
10
|
+
import { test, describe, openAndClose } from '@dxos/test';
|
|
10
11
|
|
|
11
12
|
import { protocol } from './defs';
|
|
12
13
|
import { EdgeClient } from './edge-client';
|
|
13
|
-
import {
|
|
14
|
+
import { createTestWsServer } from './test-utils';
|
|
15
|
+
|
|
16
|
+
chai.use(chaiAsPromised);
|
|
14
17
|
|
|
15
18
|
describe('EdgeClient', () => {
|
|
16
19
|
const textMessage = (message: string) => protocol.createMessage(TextMessageSchema, { payload: { message } });
|
|
17
20
|
|
|
18
21
|
test('reconnects on error', async () => {
|
|
19
|
-
const {
|
|
20
|
-
onTestFinished(cleanup);
|
|
21
|
-
|
|
22
|
+
const { error: serverError, endpoint } = await createTestWsServer();
|
|
22
23
|
const id = PublicKey.random().toHex();
|
|
23
24
|
const client = new EdgeClient(id, id, { socketEndpoint: endpoint });
|
|
24
25
|
await openAndClose(client);
|
|
@@ -26,14 +27,13 @@ describe('EdgeClient', () => {
|
|
|
26
27
|
expect(client.isOpen).is.true;
|
|
27
28
|
|
|
28
29
|
const reconnected = client.reconnect.waitForCount(1);
|
|
29
|
-
await
|
|
30
|
+
await serverError();
|
|
30
31
|
await reconnected;
|
|
31
|
-
await expect(client.send(textMessage('Hello world 2'))).
|
|
32
|
+
await expect(client.send(textMessage('Hello world 2'))).to.be.fulfilled;
|
|
32
33
|
});
|
|
33
34
|
|
|
34
35
|
test('set identity reconnects', async () => {
|
|
35
|
-
const { endpoint
|
|
36
|
-
onTestFinished(cleanup);
|
|
36
|
+
const { endpoint } = await createTestWsServer();
|
|
37
37
|
|
|
38
38
|
const id = PublicKey.random().toHex();
|
|
39
39
|
const client = new EdgeClient(id, id, { socketEndpoint: endpoint });
|
|
@@ -45,6 +45,6 @@ describe('EdgeClient', () => {
|
|
|
45
45
|
const reconnected = client.reconnect.waitForCount(1);
|
|
46
46
|
client.setIdentity({ peerKey: newId, identityKey: newId });
|
|
47
47
|
await reconnected;
|
|
48
|
-
await expect(client.send(textMessage('Hello world 2'))).
|
|
48
|
+
await expect(client.send(textMessage('Hello world 2'))).to.be.fulfilled;
|
|
49
49
|
});
|
|
50
50
|
});
|
package/src/edge-client.ts
CHANGED
|
@@ -6,12 +6,13 @@ import WebSocket from 'isomorphic-ws';
|
|
|
6
6
|
|
|
7
7
|
import { Trigger, Event, scheduleTaskInterval, scheduleTask, TriggerState } from '@dxos/async';
|
|
8
8
|
import { Context, LifecycleState, Resource, type Lifecycle } from '@dxos/context';
|
|
9
|
+
import { invariant } from '@dxos/invariant';
|
|
9
10
|
import { log } from '@dxos/log';
|
|
10
11
|
import { buf } from '@dxos/protocols/buf';
|
|
11
12
|
import { type Message, MessageSchema } from '@dxos/protocols/buf/dxos/edge/messenger_pb';
|
|
12
13
|
|
|
13
14
|
import { protocol } from './defs';
|
|
14
|
-
import {
|
|
15
|
+
import { WebsocketClosedError } from './errors';
|
|
15
16
|
import { PersistentLifecycle } from './persistent-lifecycle';
|
|
16
17
|
import { type Protocol, toUint8Array } from './protocol';
|
|
17
18
|
|
|
@@ -21,7 +22,6 @@ const SIGNAL_KEEPALIVE_INTERVAL = 5_000;
|
|
|
21
22
|
export type MessageListener = (message: Message) => void | Promise<void>;
|
|
22
23
|
|
|
23
24
|
export interface EdgeConnection extends Required<Lifecycle> {
|
|
24
|
-
connected: Event;
|
|
25
25
|
reconnect: Event;
|
|
26
26
|
|
|
27
27
|
get info(): any;
|
|
@@ -43,8 +43,7 @@ export type MessengerConfig = {
|
|
|
43
43
|
* Messenger client.
|
|
44
44
|
*/
|
|
45
45
|
export class EdgeClient extends Resource implements EdgeConnection {
|
|
46
|
-
public
|
|
47
|
-
public readonly connected = new Event();
|
|
46
|
+
public reconnect = new Event();
|
|
48
47
|
private readonly _persistentLifecycle = new PersistentLifecycle({
|
|
49
48
|
start: async () => this._openWebSocket(),
|
|
50
49
|
stop: async () => this._closeWebSocket(),
|
|
@@ -52,6 +51,7 @@ export class EdgeClient extends Resource implements EdgeConnection {
|
|
|
52
51
|
});
|
|
53
52
|
|
|
54
53
|
private readonly _listeners = new Set<MessageListener>();
|
|
54
|
+
private readonly _protocol: Protocol;
|
|
55
55
|
private _ready = new Trigger();
|
|
56
56
|
private _ws?: WebSocket = undefined;
|
|
57
57
|
private _keepaliveCtx?: Context = undefined;
|
|
@@ -63,6 +63,7 @@ export class EdgeClient extends Resource implements EdgeConnection {
|
|
|
63
63
|
private readonly _config: MessengerConfig,
|
|
64
64
|
) {
|
|
65
65
|
super();
|
|
66
|
+
this._protocol = this._config.protocol ?? protocol;
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
// TODO(burdon): Attach logging.
|
|
@@ -118,7 +119,6 @@ export class EdgeClient extends Resource implements EdgeConnection {
|
|
|
118
119
|
this._ws.onopen = () => {
|
|
119
120
|
log('opened', this.info);
|
|
120
121
|
this._ready.wake();
|
|
121
|
-
this.connected.emit();
|
|
122
122
|
};
|
|
123
123
|
this._ws.onclose = () => {
|
|
124
124
|
log('closed', this.info);
|
|
@@ -170,7 +170,7 @@ export class EdgeClient extends Resource implements EdgeConnection {
|
|
|
170
170
|
return;
|
|
171
171
|
}
|
|
172
172
|
try {
|
|
173
|
-
this._ready.throw(
|
|
173
|
+
this._ready.throw(new WebsocketClosedError());
|
|
174
174
|
this._ready.reset();
|
|
175
175
|
void this._keepaliveCtx?.dispose();
|
|
176
176
|
this._keepaliveCtx = undefined;
|
|
@@ -197,19 +197,10 @@ export class EdgeClient extends Resource implements EdgeConnection {
|
|
|
197
197
|
*/
|
|
198
198
|
public async send(message: Message): Promise<void> {
|
|
199
199
|
if (this._ready.state !== TriggerState.RESOLVED) {
|
|
200
|
-
log('waiting for websocket to become ready');
|
|
201
200
|
await this._ready.wait({ timeout: this._config.timeout ?? DEFAULT_TIMEOUT });
|
|
202
201
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
206
|
-
if (
|
|
207
|
-
message.source &&
|
|
208
|
-
(message.source.peerKey !== this._peerKey || message.source.identityKey !== this.identityKey)
|
|
209
|
-
) {
|
|
210
|
-
throw new EdgeIdentityChangedError();
|
|
211
|
-
}
|
|
212
|
-
|
|
202
|
+
invariant(this._ws);
|
|
203
|
+
invariant(!message.source || message.source.peerKey === this._peerKey);
|
|
213
204
|
log('sending...', { peerKey: this._peerKey, payload: protocol.getPayloadType(message) });
|
|
214
205
|
this._ws.send(buf.toBinary(MessageSchema, message));
|
|
215
206
|
}
|
package/src/errors.ts
CHANGED
|
@@ -2,14 +2,8 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
export class
|
|
5
|
+
export class WebsocketClosedError extends Error {
|
|
6
6
|
constructor() {
|
|
7
|
-
super('
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export class EdgeIdentityChangedError extends Error {
|
|
12
|
-
constructor() {
|
|
13
|
-
super('Edge identity changed.');
|
|
7
|
+
super('WebSocket connection closed');
|
|
14
8
|
}
|
|
15
9
|
}
|
package/src/index.ts
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { expect } from 'chai';
|
|
6
6
|
|
|
7
7
|
import { sleep, Trigger } from '@dxos/async';
|
|
8
8
|
import { log } from '@dxos/log';
|
|
9
|
-
import { openAndClose } from '@dxos/test
|
|
9
|
+
import { describe, openAndClose, test } from '@dxos/test';
|
|
10
10
|
|
|
11
11
|
import { PersistentLifecycle } from './persistent-lifecycle';
|
|
12
12
|
|
package/src/protocol.test.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { expect } from 'chai';
|
|
6
6
|
|
|
7
7
|
import { buf } from '@dxos/protocols/buf';
|
|
8
8
|
import {
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
SwarmRequestSchema,
|
|
12
12
|
SwarmResponseSchema,
|
|
13
13
|
} from '@dxos/protocols/buf/dxos/edge/messenger_pb';
|
|
14
|
+
import { describe, test } from '@dxos/test';
|
|
14
15
|
|
|
15
16
|
import { Protocol } from './protocol';
|
|
16
17
|
|
package/src/protocol.ts
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
import { invariant } from '@dxos/invariant';
|
|
6
6
|
import { buf, bufWkt } from '@dxos/protocols/buf';
|
|
7
|
-
import { type Message, MessageSchema, type
|
|
7
|
+
import { type Message, MessageSchema, type Peer as PeerProto } from '@dxos/protocols/buf/dxos/edge/messenger_pb';
|
|
8
8
|
import { bufferToArray } from '@dxos/util';
|
|
9
9
|
|
|
10
|
-
export type PeerData =
|
|
10
|
+
export type PeerData = Partial<PeerProto>;
|
|
11
11
|
|
|
12
12
|
export const getTypename = (typeName: string) => `type.googleapis.com/${typeName}`;
|
|
13
13
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import WebSocket from 'isomorphic-ws';
|
|
6
|
+
|
|
7
|
+
import { Trigger } from '@dxos/async';
|
|
8
|
+
import { log } from '@dxos/log';
|
|
9
|
+
import { buf } from '@dxos/protocols/buf';
|
|
10
|
+
import { MessageSchema, TextMessageSchema } from '@dxos/protocols/buf/dxos/edge/messenger_pb';
|
|
11
|
+
import { afterTest } from '@dxos/test';
|
|
12
|
+
|
|
13
|
+
import { protocol } from './defs';
|
|
14
|
+
import { toUint8Array } from './protocol';
|
|
15
|
+
|
|
16
|
+
export const DEFAULT_PORT = 8080;
|
|
17
|
+
|
|
18
|
+
export const createTestWsServer = async (port = DEFAULT_PORT) => {
|
|
19
|
+
const server = new WebSocket.Server({ port });
|
|
20
|
+
let connection: WebSocket;
|
|
21
|
+
const closeTrigger = new Trigger();
|
|
22
|
+
server.on('connection', (ws) => {
|
|
23
|
+
connection = ws;
|
|
24
|
+
ws.on('error', (err) => log.catch(err));
|
|
25
|
+
ws.on('message', async (data) => {
|
|
26
|
+
if (String(data) === '__ping__') {
|
|
27
|
+
ws.send('__pong__');
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
log('message', {
|
|
31
|
+
payload: protocol.getPayload(buf.fromBinary(MessageSchema, await toUint8Array(data)), TextMessageSchema),
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
ws.on('close', () => closeTrigger.wake());
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
afterTest(() => server.close());
|
|
38
|
+
return {
|
|
39
|
+
server,
|
|
40
|
+
/**
|
|
41
|
+
* Close the server connection.
|
|
42
|
+
*/
|
|
43
|
+
error: async () => {
|
|
44
|
+
connection.close(1011);
|
|
45
|
+
await closeTrigger.wait();
|
|
46
|
+
},
|
|
47
|
+
endpoint: `ws://localhost:${port}`,
|
|
48
|
+
};
|
|
49
|
+
};
|
package/src/websocket.test.ts
CHANGED
|
@@ -2,18 +2,17 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { expect } from 'chai';
|
|
5
6
|
import WebSocket from 'isomorphic-ws';
|
|
6
|
-
import { describe, expect, test, onTestFinished } from 'vitest';
|
|
7
7
|
|
|
8
8
|
import { Trigger, TriggerState } from '@dxos/async';
|
|
9
|
+
import { describe, test } from '@dxos/test';
|
|
9
10
|
|
|
10
|
-
import {
|
|
11
|
+
import { createTestWsServer } from './test-utils';
|
|
11
12
|
|
|
12
13
|
describe('WebSocket', () => {
|
|
13
14
|
test('swap `onclose` handler ', async () => {
|
|
14
|
-
const { endpoint
|
|
15
|
-
onTestFinished(cleanup);
|
|
16
|
-
|
|
15
|
+
const { endpoint } = await createTestWsServer();
|
|
17
16
|
const ws = new WebSocket(endpoint);
|
|
18
17
|
const opened = new Trigger();
|
|
19
18
|
ws.onopen = () => {
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
// packages/core/mesh/edge-client/src/protocol.ts
|
|
2
|
-
import { invariant } from "@dxos/invariant";
|
|
3
|
-
import { buf, bufWkt } from "@dxos/protocols/buf";
|
|
4
|
-
import { MessageSchema } from "@dxos/protocols/buf/dxos/edge/messenger_pb";
|
|
5
|
-
import { bufferToArray } from "@dxos/util";
|
|
6
|
-
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/protocol.ts";
|
|
7
|
-
var getTypename = (typeName) => `type.googleapis.com/${typeName}`;
|
|
8
|
-
var Protocol = class {
|
|
9
|
-
constructor(types) {
|
|
10
|
-
this._typeRegistry = buf.createRegistry(...types);
|
|
11
|
-
}
|
|
12
|
-
get typeRegistry() {
|
|
13
|
-
return this._typeRegistry;
|
|
14
|
-
}
|
|
15
|
-
toJson(message) {
|
|
16
|
-
try {
|
|
17
|
-
return buf.toJson(MessageSchema, message, {
|
|
18
|
-
registry: this.typeRegistry
|
|
19
|
-
});
|
|
20
|
-
} catch (err) {
|
|
21
|
-
return {
|
|
22
|
-
type: this.getPayloadType(message)
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Return the payload with the given type.
|
|
28
|
-
*/
|
|
29
|
-
getPayload(message, type) {
|
|
30
|
-
invariant(message.payload, void 0, {
|
|
31
|
-
F: __dxlog_file,
|
|
32
|
-
L: 40,
|
|
33
|
-
S: this,
|
|
34
|
-
A: [
|
|
35
|
-
"message.payload",
|
|
36
|
-
""
|
|
37
|
-
]
|
|
38
|
-
});
|
|
39
|
-
const payloadTypename = this.getPayloadType(message);
|
|
40
|
-
if (type && type.typeName !== payloadTypename) {
|
|
41
|
-
throw new Error(`Unexpected payload type: ${payloadTypename}; expected ${type.typeName}`);
|
|
42
|
-
}
|
|
43
|
-
invariant(bufWkt.anyIs(message.payload, type), `Unexpected payload type: ${payloadTypename}}`, {
|
|
44
|
-
F: __dxlog_file,
|
|
45
|
-
L: 46,
|
|
46
|
-
S: this,
|
|
47
|
-
A: [
|
|
48
|
-
"bufWkt.anyIs(message.payload, type)",
|
|
49
|
-
"`Unexpected payload type: ${payloadTypename}}`"
|
|
50
|
-
]
|
|
51
|
-
});
|
|
52
|
-
const payload = bufWkt.anyUnpack(message.payload, this.typeRegistry);
|
|
53
|
-
invariant(payload, `Empty payload: ${payloadTypename}}`, {
|
|
54
|
-
F: __dxlog_file,
|
|
55
|
-
L: 48,
|
|
56
|
-
S: this,
|
|
57
|
-
A: [
|
|
58
|
-
"payload",
|
|
59
|
-
"`Empty payload: ${payloadTypename}}`"
|
|
60
|
-
]
|
|
61
|
-
});
|
|
62
|
-
return payload;
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Get the payload type.
|
|
66
|
-
*/
|
|
67
|
-
getPayloadType(message) {
|
|
68
|
-
if (!message.payload) {
|
|
69
|
-
return void 0;
|
|
70
|
-
}
|
|
71
|
-
const [, type] = message.payload.typeUrl.split("/");
|
|
72
|
-
return type;
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Create a packed message.
|
|
76
|
-
*/
|
|
77
|
-
createMessage(type, { source, target, payload, serviceId }) {
|
|
78
|
-
return buf.create(MessageSchema, {
|
|
79
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
80
|
-
source,
|
|
81
|
-
target,
|
|
82
|
-
serviceId,
|
|
83
|
-
payload: payload ? bufWkt.anyPack(type, buf.create(type, payload)) : void 0
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
var toUint8Array = async (data) => {
|
|
88
|
-
if (data instanceof Buffer) {
|
|
89
|
-
return bufferToArray(data);
|
|
90
|
-
}
|
|
91
|
-
if (data instanceof Blob) {
|
|
92
|
-
return new Uint8Array(await data.arrayBuffer());
|
|
93
|
-
}
|
|
94
|
-
throw new Error(`Unexpected datatype: ${data}`);
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
// packages/core/mesh/edge-client/src/defs.ts
|
|
98
|
-
import { bufWkt as bufWkt2 } from "@dxos/protocols/buf";
|
|
99
|
-
import { SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema } from "@dxos/protocols/buf/dxos/edge/messenger_pb";
|
|
100
|
-
var protocol = new Protocol([
|
|
101
|
-
SwarmRequestSchema,
|
|
102
|
-
SwarmResponseSchema,
|
|
103
|
-
TextMessageSchema,
|
|
104
|
-
bufWkt2.AnySchema
|
|
105
|
-
]);
|
|
106
|
-
|
|
107
|
-
export {
|
|
108
|
-
getTypename,
|
|
109
|
-
Protocol,
|
|
110
|
-
toUint8Array,
|
|
111
|
-
protocol
|
|
112
|
-
};
|
|
113
|
-
//# sourceMappingURL=chunk-ZWJXA37R.mjs.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/protocol.ts", "../../../src/defs.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { invariant } from '@dxos/invariant';\nimport { buf, bufWkt } from '@dxos/protocols/buf';\nimport { type Message, MessageSchema, type PeerSchema } from '@dxos/protocols/buf/dxos/edge/messenger_pb';\nimport { bufferToArray } from '@dxos/util';\n\nexport type PeerData = buf.MessageInitShape<typeof PeerSchema>;\n\nexport const getTypename = (typeName: string) => `type.googleapis.com/${typeName}`;\n\n/**\n * NOTE: The type registry should be extended with all message types.\n */\nexport class Protocol {\n private readonly _typeRegistry: buf.Registry;\n\n constructor(types: buf.DescMessage[]) {\n this._typeRegistry = buf.createRegistry(...types);\n }\n\n get typeRegistry(): buf.Registry {\n return this._typeRegistry;\n }\n\n toJson(message: Message): any {\n try {\n return buf.toJson(MessageSchema, message, { registry: this.typeRegistry });\n } catch (err) {\n return { type: this.getPayloadType(message) };\n }\n }\n\n /**\n * Return the payload with the given type.\n */\n getPayload<Desc extends buf.DescMessage>(message: Message, type: Desc): buf.MessageShape<Desc> {\n invariant(message.payload);\n const payloadTypename = this.getPayloadType(message);\n if (type && type.typeName !== payloadTypename) {\n throw new Error(`Unexpected payload type: ${payloadTypename}; expected ${type.typeName}`);\n }\n\n invariant(bufWkt.anyIs(message.payload, type), `Unexpected payload type: ${payloadTypename}}`);\n const payload = bufWkt.anyUnpack(message.payload, this.typeRegistry) as buf.MessageShape<Desc>;\n invariant(payload, `Empty payload: ${payloadTypename}}`);\n return payload;\n }\n\n /**\n * Get the payload type.\n */\n getPayloadType(message: Message): string | undefined {\n if (!message.payload) {\n return undefined;\n }\n\n const [, type] = message.payload.typeUrl.split('/');\n return type;\n }\n\n /**\n * Create a packed message.\n */\n createMessage<Desc extends buf.DescMessage>(\n type: Desc,\n {\n source,\n target,\n payload,\n serviceId,\n }: {\n source?: PeerData;\n target?: PeerData[];\n payload?: buf.MessageInitShape<Desc>;\n serviceId?: string;\n },\n ) {\n return buf.create(MessageSchema, {\n timestamp: new Date().toISOString(),\n source,\n target,\n serviceId,\n payload: payload ? bufWkt.anyPack(type, buf.create(type, payload)) : undefined,\n });\n }\n}\n\n/**\n * Convert websocket data to Uint8Array.\n */\nexport const toUint8Array = async (data: any): Promise<Uint8Array> => {\n // Node.\n if (data instanceof Buffer) {\n return bufferToArray(data);\n }\n\n // Browser.\n if (data instanceof Blob) {\n return new Uint8Array(await (data as Blob).arrayBuffer());\n }\n\n throw new Error(`Unexpected datatype: ${data}`);\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { bufWkt } from '@dxos/protocols/buf';\nimport { SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema } from '@dxos/protocols/buf/dxos/edge/messenger_pb';\n\nimport { Protocol } from './protocol';\n\nexport const protocol = new Protocol([SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema, bufWkt.AnySchema]);\n"],
|
|
5
|
-
"mappings": ";AAIA,SAASA,iBAAiB;AAC1B,SAASC,KAAKC,cAAc;AAC5B,SAAuBC,qBAAsC;AAC7D,SAASC,qBAAqB;;AAIvB,IAAMC,cAAc,CAACC,aAAqB,uBAAuBA,QAAAA;AAKjE,IAAMC,WAAN,MAAMA;EAGXC,YAAYC,OAA0B;AACpC,SAAKC,gBAAgBT,IAAIU,eAAc,GAAIF,KAAAA;EAC7C;EAEA,IAAIG,eAA6B;AAC/B,WAAO,KAAKF;EACd;EAEAG,OAAOC,SAAuB;AAC5B,QAAI;AACF,aAAOb,IAAIY,OAAOV,eAAeW,SAAS;QAAEC,UAAU,KAAKH;MAAa,CAAA;IAC1E,SAASI,KAAK;AACZ,aAAO;QAAEC,MAAM,KAAKC,eAAeJ,OAAAA;MAAS;IAC9C;EACF;;;;EAKAK,WAAyCL,SAAkBG,MAAoC;AAC7FjB,cAAUc,QAAQM,SAAO,QAAA;;;;;;;;;AACzB,UAAMC,kBAAkB,KAAKH,eAAeJ,OAAAA;AAC5C,QAAIG,QAAQA,KAAKX,aAAae,iBAAiB;AAC7C,YAAM,IAAIC,MAAM,4BAA4BD,eAAAA,cAA6BJ,KAAKX,QAAQ,EAAE;IAC1F;AAEAN,cAAUE,OAAOqB,MAAMT,QAAQM,SAASH,IAAAA,GAAO,4BAA4BI,eAAAA,KAAkB;;;;;;;;;AAC7F,UAAMD,UAAUlB,OAAOsB,UAAUV,QAAQM,SAAS,KAAKR,YAAY;AACnEZ,cAAUoB,SAAS,kBAAkBC,eAAAA,KAAkB;;;;;;;;;AACvD,WAAOD;EACT;;;;EAKAF,eAAeJ,SAAsC;AACnD,QAAI,CAACA,QAAQM,SAAS;AACpB,aAAOK;IACT;AAEA,UAAM,CAAA,EAAGR,IAAAA,IAAQH,QAAQM,QAAQM,QAAQC,MAAM,GAAA;AAC/C,WAAOV;EACT;;;;EAKAW,cACEX,MACA,EACEY,QACAC,QACAV,SACAW,UAAS,GAOX;AACA,WAAO9B,IAAI+B,OAAO7B,eAAe;MAC/B8B,YAAW,oBAAIC,KAAAA,GAAOC,YAAW;MACjCN;MACAC;MACAC;MACAX,SAASA,UAAUlB,OAAOkC,QAAQnB,MAAMhB,IAAI+B,OAAOf,MAAMG,OAAAA,CAAAA,IAAYK;IACvE,CAAA;EACF;AACF;AAKO,IAAMY,eAAe,OAAOC,SAAAA;AAEjC,MAAIA,gBAAgBC,QAAQ;AAC1B,WAAOnC,cAAckC,IAAAA;EACvB;AAGA,MAAIA,gBAAgBE,MAAM;AACxB,WAAO,IAAIC,WAAW,MAAOH,KAAcI,YAAW,CAAA;EACxD;AAEA,QAAM,IAAIpB,MAAM,wBAAwBgB,IAAAA,EAAM;AAChD;;;ACrGA,SAASK,UAAAA,eAAc;AACvB,SAASC,oBAAoBC,qBAAqBC,yBAAyB;AAIpE,IAAMC,WAAW,IAAIC,SAAS;EAACC;EAAoBC;EAAqBC;EAAmBC,QAAOC;CAAU;",
|
|
6
|
-
"names": ["invariant", "buf", "bufWkt", "MessageSchema", "bufferToArray", "getTypename", "typeName", "Protocol", "constructor", "types", "_typeRegistry", "createRegistry", "typeRegistry", "toJson", "message", "registry", "err", "type", "getPayloadType", "getPayload", "payload", "payloadTypename", "Error", "anyIs", "anyUnpack", "undefined", "typeUrl", "split", "createMessage", "source", "target", "serviceId", "create", "timestamp", "Date", "toISOString", "anyPack", "toUint8Array", "data", "Buffer", "Blob", "Uint8Array", "arrayBuffer", "bufWkt", "SwarmRequestSchema", "SwarmResponseSchema", "TextMessageSchema", "protocol", "Protocol", "SwarmRequestSchema", "SwarmResponseSchema", "TextMessageSchema", "bufWkt", "AnySchema"]
|
|
7
|
-
}
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
protocol,
|
|
3
|
-
toUint8Array
|
|
4
|
-
} from "../chunk-ZWJXA37R.mjs";
|
|
5
|
-
|
|
6
|
-
// packages/core/mesh/edge-client/src/testing/test-utils.ts
|
|
7
|
-
import WebSocket from "isomorphic-ws";
|
|
8
|
-
import { Trigger } from "@dxos/async";
|
|
9
|
-
import { log } from "@dxos/log";
|
|
10
|
-
import { buf } from "@dxos/protocols/buf";
|
|
11
|
-
import { MessageSchema, TextMessageSchema } from "@dxos/protocols/buf/dxos/edge/messenger_pb";
|
|
12
|
-
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/testing/test-utils.ts";
|
|
13
|
-
var DEFAULT_PORT = 8080;
|
|
14
|
-
var createTestEdgeWsServer = async (port = DEFAULT_PORT, params) => {
|
|
15
|
-
const server = new WebSocket.Server({
|
|
16
|
-
port,
|
|
17
|
-
verifyClient: createConnectionDelayHandler(params)
|
|
18
|
-
});
|
|
19
|
-
let connection;
|
|
20
|
-
const messageSink = [];
|
|
21
|
-
const closeTrigger = new Trigger();
|
|
22
|
-
const sendResponseMessage = createResponseSender(() => connection);
|
|
23
|
-
server.on("connection", (ws) => {
|
|
24
|
-
connection = ws;
|
|
25
|
-
ws.on("error", (err) => log.catch(err, void 0, {
|
|
26
|
-
F: __dxlog_file,
|
|
27
|
-
L: 34,
|
|
28
|
-
S: void 0,
|
|
29
|
-
C: (f, a) => f(...a)
|
|
30
|
-
}));
|
|
31
|
-
ws.on("message", async (data) => {
|
|
32
|
-
if (String(data) === "__ping__") {
|
|
33
|
-
ws.send("__pong__");
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
const { request, requestPayload } = await decodeRequest(params, data);
|
|
37
|
-
if (params?.messageHandler) {
|
|
38
|
-
const responsePayload = await params.messageHandler(requestPayload);
|
|
39
|
-
if (responsePayload && connection) {
|
|
40
|
-
sendResponseMessage(request, responsePayload);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
log("message", {
|
|
44
|
-
payload: requestPayload
|
|
45
|
-
}, {
|
|
46
|
-
F: __dxlog_file,
|
|
47
|
-
L: 47,
|
|
48
|
-
S: void 0,
|
|
49
|
-
C: (f, a) => f(...a)
|
|
50
|
-
});
|
|
51
|
-
messageSink.push(requestPayload);
|
|
52
|
-
});
|
|
53
|
-
ws.on("close", () => {
|
|
54
|
-
connection = void 0;
|
|
55
|
-
closeTrigger.wake();
|
|
56
|
-
});
|
|
57
|
-
});
|
|
58
|
-
return {
|
|
59
|
-
server,
|
|
60
|
-
messageSink,
|
|
61
|
-
endpoint: `ws://localhost:${port}`,
|
|
62
|
-
cleanup: () => server.close(),
|
|
63
|
-
currentConnection: () => connection,
|
|
64
|
-
sendResponseMessage,
|
|
65
|
-
closeConnection: () => {
|
|
66
|
-
closeTrigger.reset();
|
|
67
|
-
connection.close(1011);
|
|
68
|
-
return closeTrigger.wait();
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
};
|
|
72
|
-
var createConnectionDelayHandler = (params) => {
|
|
73
|
-
return (_, callback) => {
|
|
74
|
-
if (params?.admitConnection) {
|
|
75
|
-
log("delaying edge connection admission", void 0, {
|
|
76
|
-
F: __dxlog_file,
|
|
77
|
-
L: 75,
|
|
78
|
-
S: void 0,
|
|
79
|
-
C: (f, a) => f(...a)
|
|
80
|
-
});
|
|
81
|
-
void params.admitConnection.wait().then(() => {
|
|
82
|
-
callback(true);
|
|
83
|
-
log("edge connection admitted", void 0, {
|
|
84
|
-
F: __dxlog_file,
|
|
85
|
-
L: 78,
|
|
86
|
-
S: void 0,
|
|
87
|
-
C: (f, a) => f(...a)
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
} else {
|
|
91
|
-
callback(true);
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
};
|
|
95
|
-
var createResponseSender = (connection) => {
|
|
96
|
-
return (request, responsePayload) => {
|
|
97
|
-
const recipient = request.source;
|
|
98
|
-
connection().send(buf.toBinary(MessageSchema, buf.create(MessageSchema, {
|
|
99
|
-
source: {
|
|
100
|
-
identityKey: recipient.identityKey,
|
|
101
|
-
peerKey: recipient.peerKey
|
|
102
|
-
},
|
|
103
|
-
serviceId: request.serviceId,
|
|
104
|
-
payload: {
|
|
105
|
-
value: responsePayload
|
|
106
|
-
}
|
|
107
|
-
})));
|
|
108
|
-
};
|
|
109
|
-
};
|
|
110
|
-
var decodeRequest = async (params, data) => {
|
|
111
|
-
const request = buf.fromBinary(MessageSchema, await toUint8Array(data));
|
|
112
|
-
const requestPayload = params?.payloadDecoder ? params.payloadDecoder(request.payload.value) : protocol.getPayload(request, TextMessageSchema);
|
|
113
|
-
return {
|
|
114
|
-
request,
|
|
115
|
-
requestPayload
|
|
116
|
-
};
|
|
117
|
-
};
|
|
118
|
-
export {
|
|
119
|
-
DEFAULT_PORT,
|
|
120
|
-
createTestEdgeWsServer
|
|
121
|
-
};
|
|
122
|
-
//# sourceMappingURL=index.mjs.map
|