@dxos/messaging 0.4.10-main.fd4f2a3 → 0.4.10-main.fd8ea31
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 +69 -64
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +69 -64
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/meta.json +1 -1
- package/dist/types/src/signal-client/signal-client.d.ts +5 -13
- package/dist/types/src/signal-client/signal-client.d.ts.map +1 -1
- package/dist/types/src/signal-manager/memory-signal-manager.d.ts +2 -1
- package/dist/types/src/signal-manager/memory-signal-manager.d.ts.map +1 -1
- package/dist/types/src/signal-manager/signal-manager.d.ts +6 -6
- package/dist/types/src/signal-manager/signal-manager.d.ts.map +1 -1
- package/dist/types/src/signal-manager/websocket-signal-manager.d.ts +2 -1
- package/dist/types/src/signal-manager/websocket-signal-manager.d.ts.map +1 -1
- package/dist/types/src/signal-methods.d.ts +20 -0
- package/dist/types/src/signal-methods.d.ts.map +1 -1
- package/package.json +12 -12
- package/src/signal-client/signal-client.test.ts +14 -14
- package/src/signal-client/signal-client.ts +9 -18
- package/src/signal-manager/memory-signal-manager.ts +2 -1
- package/src/signal-manager/signal-manager.ts +8 -8
- package/src/signal-manager/websocket-signal-manager.ts +16 -9
- package/src/signal-methods.ts +22 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"websocket-signal-manager.d.ts","sourceRoot":"","sources":["../../../../src/signal-manager/websocket-signal-manager.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,EAAuB,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAGhD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvC,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,wCAAwC,CAAC;AAEzE,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,KAAK,YAAY,EAAgB,KAAK,YAAY,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"websocket-signal-manager.d.ts","sourceRoot":"","sources":["../../../../src/signal-manager/websocket-signal-manager.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,EAAuB,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAGhD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvC,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,wCAAwC,CAAC;AAEzE,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,KAAK,YAAY,EAAgB,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAgD,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAKpG;;GAEG;AACH,qBAAa,sBAAuB,YAAW,aAAa;IAuBxD,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;IAvBhC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA0C;IAEnE,OAAO,CAAC,IAAI,CAAW;IACvB,OAAO,CAAC,OAAO,CAAS;IAExB,QAAQ,CAAC,YAAY,sBAA6B;IAClD,QAAQ,CAAC,aAAa,wBAA+B;IACrD,QAAQ,CAAC,YAAY,sBAA6B;IAClD,QAAQ,CAAC,UAAU;eACV,SAAS;oBACJ,UAAU;OACnB;IAEL,QAAQ,CAAC,SAAS;gBACR,SAAS;mBACN,SAAS;iBACX,GAAG;OACT;IAEL,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA8B;gBAGvC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,MAAM,EAAE,EACjC,YAAY,CAAC,SAAQ,GAAG,aAAA;IAyBrC,IAAI;IAiBJ,KAAK;IAWL,aAAa,CAAC,UAAU,EAAE,MAAM;IAYtC,SAAS,IAAI,YAAY,EAAE;IAKrB,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;QAAE,KAAK,EAAE,SAAS,CAAC;QAAC,MAAM,EAAE,SAAS,CAAA;KAAE;IAO/D,KAAK,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;QAAE,KAAK,EAAE,SAAS,CAAC;QAAC,MAAM,EAAE,SAAS,CAAA;KAAE;IAOhE,WAAW,CAAC,EAChB,MAAM,EACN,SAAS,EACT,OAAO,GACR,EAAE;QACD,MAAM,EAAE,SAAS,CAAC;QAClB,SAAS,EAAE,SAAS,CAAC;QACrB,OAAO,EAAE,GAAG,CAAC;KACd,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBX,kBAAkB,CAAC,UAAU,EAAE,MAAM;IAYrC,iBAAiB,CAAC,MAAM,EAAE,SAAS;IAOnC,mBAAmB,CAAC,MAAM,EAAE,SAAS;IAO3C,OAAO,CAAC,YAAY;YAMN,cAAc;CAK7B"}
|
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
import { type Any } from '@dxos/codec-protobuf';
|
|
2
2
|
import { type PublicKey } from '@dxos/keys';
|
|
3
|
+
import { type SignalState } from '@dxos/protocols/proto/dxos/mesh/signal';
|
|
3
4
|
export interface Message {
|
|
4
5
|
author: PublicKey;
|
|
5
6
|
recipient: PublicKey;
|
|
6
7
|
payload: Any;
|
|
7
8
|
}
|
|
9
|
+
export type SignalStatus = {
|
|
10
|
+
host: string;
|
|
11
|
+
state: SignalState;
|
|
12
|
+
error?: string;
|
|
13
|
+
reconnectIn: number;
|
|
14
|
+
connectionStarted: Date;
|
|
15
|
+
lastStateChange: Date;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Message routing interface.
|
|
19
|
+
*/
|
|
8
20
|
export interface SignalMethods {
|
|
9
21
|
/**
|
|
10
22
|
* Join topic on signal network, to be discoverable by other peers.
|
|
@@ -33,4 +45,12 @@ export interface SignalMethods {
|
|
|
33
45
|
*/
|
|
34
46
|
unsubscribeMessages: (peerId: PublicKey) => Promise<void>;
|
|
35
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Signaling client.
|
|
50
|
+
*/
|
|
51
|
+
export interface SignalClientMethods extends SignalMethods {
|
|
52
|
+
open(): Promise<void>;
|
|
53
|
+
close(): Promise<void>;
|
|
54
|
+
getStatus(): SignalStatus;
|
|
55
|
+
}
|
|
36
56
|
//# sourceMappingURL=signal-methods.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signal-methods.d.ts","sourceRoot":"","sources":["../../../src/signal-methods.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"signal-methods.d.ts","sourceRoot":"","sources":["../../../src/signal-methods.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,wCAAwC,CAAC;AAE1E,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,SAAS,CAAC;IAClB,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,GAAG,CAAC;CACd;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,WAAW,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,IAAI,CAAC;IACxB,eAAe,EAAE,IAAI,CAAC;CACvB,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,IAAI,EAAE,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,SAAS,CAAC;QAAC,MAAM,EAAE,SAAS,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzE;;OAEG;IACH,KAAK,EAAE,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,SAAS,CAAC;QAAC,MAAM,EAAE,SAAS,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1E;;OAEG;IACH,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjD;;OAEG;IACH,iBAAiB,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAExD;;OAEG;IACH,mBAAmB,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3D;AAED;;GAEG;AACH,MAAM,WAAW,mBAAoB,SAAQ,aAAa;IACxD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,SAAS,IAAI,YAAY,CAAC;CAC3B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/messaging",
|
|
3
|
-
"version": "0.4.10-main.
|
|
3
|
+
"version": "0.4.10-main.fd8ea31",
|
|
4
4
|
"description": "Messaging",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -19,23 +19,23 @@
|
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"isomorphic-ws": "^4.0.1",
|
|
21
21
|
"ws": "^8.14.2",
|
|
22
|
-
"@dxos/
|
|
23
|
-
"@dxos/
|
|
24
|
-
"@dxos/
|
|
25
|
-
"@dxos/
|
|
26
|
-
"@dxos/log": "0.4.10-main.
|
|
27
|
-
"@dxos/
|
|
28
|
-
"@dxos/node-std": "0.4.10-main.
|
|
29
|
-
"@dxos/
|
|
30
|
-
"@dxos/
|
|
31
|
-
"@dxos/
|
|
22
|
+
"@dxos/async": "0.4.10-main.fd8ea31",
|
|
23
|
+
"@dxos/context": "0.4.10-main.fd8ea31",
|
|
24
|
+
"@dxos/codec-protobuf": "0.4.10-main.fd8ea31",
|
|
25
|
+
"@dxos/invariant": "0.4.10-main.fd8ea31",
|
|
26
|
+
"@dxos/log": "0.4.10-main.fd8ea31",
|
|
27
|
+
"@dxos/keys": "0.4.10-main.fd8ea31",
|
|
28
|
+
"@dxos/node-std": "0.4.10-main.fd8ea31",
|
|
29
|
+
"@dxos/rpc": "0.4.10-main.fd8ea31",
|
|
30
|
+
"@dxos/util": "0.4.10-main.fd8ea31",
|
|
31
|
+
"@dxos/protocols": "0.4.10-main.fd8ea31"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/node": "^18.11.9",
|
|
35
35
|
"earljs": "~0.1.10",
|
|
36
36
|
"typescript": "^5.2.2",
|
|
37
37
|
"wait-for-expect": "^3.0.2",
|
|
38
|
-
"@dxos/signal": "0.4.10-main.
|
|
38
|
+
"@dxos/signal": "0.4.10-main.fd8ea31"
|
|
39
39
|
},
|
|
40
40
|
"publishConfig": {
|
|
41
41
|
"access": "public"
|
|
@@ -52,10 +52,10 @@ describe('SignalClient', () => {
|
|
|
52
52
|
},
|
|
53
53
|
async () => {},
|
|
54
54
|
);
|
|
55
|
-
api1.open();
|
|
55
|
+
void api1.open();
|
|
56
56
|
afterTest(() => api1.close());
|
|
57
57
|
const api2 = new SignalClient(broker1.url(), (async () => {}) as any, async () => {});
|
|
58
|
-
api2.open();
|
|
58
|
+
void api2.open();
|
|
59
59
|
afterTest(() => api2.close());
|
|
60
60
|
|
|
61
61
|
await api1.subscribeMessages(peer1);
|
|
@@ -87,7 +87,7 @@ describe('SignalClient', () => {
|
|
|
87
87
|
}
|
|
88
88
|
},
|
|
89
89
|
);
|
|
90
|
-
api1.open();
|
|
90
|
+
void api1.open();
|
|
91
91
|
afterTest(() => api1.close());
|
|
92
92
|
|
|
93
93
|
const trigger2 = new Trigger();
|
|
@@ -100,7 +100,7 @@ describe('SignalClient', () => {
|
|
|
100
100
|
}
|
|
101
101
|
},
|
|
102
102
|
);
|
|
103
|
-
api2.open();
|
|
103
|
+
void api2.open();
|
|
104
104
|
afterTest(() => api2.close());
|
|
105
105
|
await api1.join({ topic, peerId: peer1 });
|
|
106
106
|
await api2.join({ topic, peerId: peer2 });
|
|
@@ -122,7 +122,7 @@ describe('SignalClient', () => {
|
|
|
122
122
|
},
|
|
123
123
|
async () => {},
|
|
124
124
|
);
|
|
125
|
-
api1.open();
|
|
125
|
+
void api1.open();
|
|
126
126
|
afterTest(() => api1.close());
|
|
127
127
|
|
|
128
128
|
await api1.subscribeMessages(peer1);
|
|
@@ -150,11 +150,11 @@ describe('SignalClient', () => {
|
|
|
150
150
|
},
|
|
151
151
|
async () => {},
|
|
152
152
|
);
|
|
153
|
-
client1.open();
|
|
153
|
+
void client1.open();
|
|
154
154
|
afterTest(() => client1.close());
|
|
155
155
|
|
|
156
156
|
const client2 = new SignalClient(broker1.url(), (async () => {}) as any, async () => {});
|
|
157
|
-
client2.open();
|
|
157
|
+
void client2.open();
|
|
158
158
|
afterTest(() => client2.close());
|
|
159
159
|
|
|
160
160
|
await client1.subscribeMessages(peer1);
|
|
@@ -203,11 +203,11 @@ describe('SignalClient', () => {
|
|
|
203
203
|
},
|
|
204
204
|
async () => {},
|
|
205
205
|
);
|
|
206
|
-
client1.open();
|
|
206
|
+
void client1.open();
|
|
207
207
|
afterTest(() => client1.close());
|
|
208
208
|
|
|
209
209
|
const client2 = new SignalClient(broker1.url(), (async () => {}) as any, async () => {});
|
|
210
|
-
client2.open();
|
|
210
|
+
void client2.open();
|
|
211
211
|
afterTest(() => client2.close());
|
|
212
212
|
|
|
213
213
|
const message = {
|
|
@@ -233,7 +233,7 @@ describe('SignalClient', () => {
|
|
|
233
233
|
//
|
|
234
234
|
|
|
235
235
|
await client1.close();
|
|
236
|
-
client1.open();
|
|
236
|
+
void client1.open();
|
|
237
237
|
await waitForSubscription(client1, peer1);
|
|
238
238
|
|
|
239
239
|
{
|
|
@@ -259,14 +259,14 @@ describe('SignalClient', () => {
|
|
|
259
259
|
async () => {},
|
|
260
260
|
async () => {},
|
|
261
261
|
);
|
|
262
|
-
api1.open();
|
|
262
|
+
void api1.open();
|
|
263
263
|
afterTest(() => api1.close());
|
|
264
264
|
const api2 = new SignalClient(
|
|
265
265
|
broker2.url(),
|
|
266
266
|
async () => {},
|
|
267
267
|
async () => {},
|
|
268
268
|
);
|
|
269
|
-
api2.open();
|
|
269
|
+
void api2.open();
|
|
270
270
|
afterTest(() => api2.close());
|
|
271
271
|
|
|
272
272
|
await api1.join({ topic, peerId: peer1 });
|
|
@@ -300,10 +300,10 @@ describe('SignalClient', () => {
|
|
|
300
300
|
async () => {},
|
|
301
301
|
async () => {},
|
|
302
302
|
);
|
|
303
|
-
api1.open();
|
|
303
|
+
void api1.open();
|
|
304
304
|
afterTest(() => api1.close());
|
|
305
305
|
const api2 = new SignalClient(broker2.url(), signalMock, async () => {});
|
|
306
|
-
api2.open();
|
|
306
|
+
void api2.open();
|
|
307
307
|
afterTest(() => api2.close());
|
|
308
308
|
|
|
309
309
|
await api1.join({ topic, peerId: peer1 });
|
|
@@ -13,22 +13,13 @@ import { type Message as SignalMessage, SignalState, type SwarmEvent } from '@dx
|
|
|
13
13
|
import { ComplexMap, ComplexSet } from '@dxos/util';
|
|
14
14
|
|
|
15
15
|
import { SignalRPCClient } from './signal-rpc-client';
|
|
16
|
-
import { type Message, type
|
|
16
|
+
import { type Message, type SignalClientMethods, type SignalStatus } from '../signal-methods';
|
|
17
17
|
|
|
18
18
|
const DEFAULT_RECONNECT_TIMEOUT = 100;
|
|
19
|
-
const MAX_RECONNECT_TIMEOUT =
|
|
20
|
-
const ERROR_RECONCILE_DELAY =
|
|
19
|
+
const MAX_RECONNECT_TIMEOUT = 5_000;
|
|
20
|
+
const ERROR_RECONCILE_DELAY = 1_000;
|
|
21
21
|
const RECONCILE_INTERVAL = 5_000;
|
|
22
22
|
|
|
23
|
-
export type SignalStatus = {
|
|
24
|
-
host: string;
|
|
25
|
-
state: SignalState;
|
|
26
|
-
error?: string;
|
|
27
|
-
reconnectIn: number;
|
|
28
|
-
connectionStarted: Date;
|
|
29
|
-
lastStateChange: Date;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
23
|
export type CommandTrace = {
|
|
33
24
|
messageId: string;
|
|
34
25
|
host: string;
|
|
@@ -41,9 +32,11 @@ export type CommandTrace = {
|
|
|
41
32
|
};
|
|
42
33
|
|
|
43
34
|
/**
|
|
35
|
+
* KUBE-specific signaling client.
|
|
44
36
|
* Establishes a websocket connection to signal server and provides RPC methods.
|
|
45
37
|
*/
|
|
46
|
-
|
|
38
|
+
// TODO(burdon): Rename impl.
|
|
39
|
+
export class SignalClient implements SignalClientMethods {
|
|
47
40
|
private _state = SignalState.CLOSED;
|
|
48
41
|
|
|
49
42
|
private _lastError?: Error;
|
|
@@ -119,7 +112,6 @@ export class SignalClient implements SignalMethods {
|
|
|
119
112
|
|
|
120
113
|
/**
|
|
121
114
|
* @param _host Signal server websocket URL.
|
|
122
|
-
* @param _onMessage
|
|
123
115
|
*/
|
|
124
116
|
constructor(
|
|
125
117
|
private readonly _host: string,
|
|
@@ -132,7 +124,7 @@ export class SignalClient implements SignalMethods {
|
|
|
132
124
|
}
|
|
133
125
|
}
|
|
134
126
|
|
|
135
|
-
open() {
|
|
127
|
+
async open() {
|
|
136
128
|
log.trace('dxos.mesh.signal-client.open', trace.begin({ id: this._instanceId }));
|
|
137
129
|
|
|
138
130
|
if ([SignalState.CONNECTED, SignalState.CONNECTING].includes(this._state)) {
|
|
@@ -213,7 +205,6 @@ export class SignalClient implements SignalMethods {
|
|
|
213
205
|
async leave({ topic, peerId }: { topic: PublicKey; peerId: PublicKey }): Promise<void> {
|
|
214
206
|
this._performance.leaveCounter++;
|
|
215
207
|
log('leaving', { topic, peerId });
|
|
216
|
-
|
|
217
208
|
void this._swarmStreams.get({ topic, peerId })?.close();
|
|
218
209
|
this._swarmStreams.delete({ topic, peerId });
|
|
219
210
|
this._joinedTopics.delete({ topic, peerId });
|
|
@@ -380,7 +371,7 @@ export class SignalClient implements SignalMethods {
|
|
|
380
371
|
|
|
381
372
|
const swarmStream = await asyncTimeout(
|
|
382
373
|
cancelWithContext(this._connectionCtx!, client.join({ topic, peerId })),
|
|
383
|
-
|
|
374
|
+
5_000,
|
|
384
375
|
);
|
|
385
376
|
// Subscribing to swarm events.
|
|
386
377
|
// TODO(mykola): What happens when the swarm stream is closed? Maybe send leave event for each peer?
|
|
@@ -419,7 +410,7 @@ export class SignalClient implements SignalMethods {
|
|
|
419
410
|
|
|
420
411
|
const messageStream = await asyncTimeout(
|
|
421
412
|
cancelWithContext(this._connectionCtx!, client.receiveMessages(peerId)),
|
|
422
|
-
|
|
413
|
+
5_000,
|
|
423
414
|
);
|
|
424
415
|
messageStream.subscribe(async (message: SignalMessage) => {
|
|
425
416
|
this._performance.receivedMessages++;
|
|
@@ -13,7 +13,8 @@ import { type SwarmEvent } from '@dxos/protocols/proto/dxos/mesh/signal';
|
|
|
13
13
|
import { ComplexMap, ComplexSet } from '@dxos/util';
|
|
14
14
|
|
|
15
15
|
import { type SignalManager } from './signal-manager';
|
|
16
|
-
import { type CommandTrace
|
|
16
|
+
import { type CommandTrace } from '../signal-client';
|
|
17
|
+
import { type SignalStatus } from '../signal-methods';
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* Common signaling context that connects multiple MemorySignalManager instances.
|
|
@@ -6,20 +6,20 @@ import { type Event } from '@dxos/async';
|
|
|
6
6
|
import { type PublicKey } from '@dxos/keys';
|
|
7
7
|
import { type SwarmEvent } from '@dxos/protocols/proto/dxos/mesh/signal';
|
|
8
8
|
|
|
9
|
-
import { type CommandTrace
|
|
10
|
-
import { type Message, type SignalMethods } from '../signal-methods';
|
|
9
|
+
import { type CommandTrace } from '../signal-client';
|
|
10
|
+
import { type Message, type SignalMethods, type SignalStatus } from '../signal-methods';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
13
|
+
* Manages a collection of signaling clients.
|
|
14
14
|
*/
|
|
15
15
|
export interface SignalManager extends SignalMethods {
|
|
16
|
+
open(): Promise<void>;
|
|
17
|
+
close(): Promise<void>;
|
|
18
|
+
|
|
19
|
+
getStatus(): SignalStatus[];
|
|
20
|
+
|
|
16
21
|
statusChanged: Event<SignalStatus[]>;
|
|
17
22
|
commandTrace: Event<CommandTrace>;
|
|
18
23
|
swarmEvent: Event<{ topic: PublicKey; swarmEvent: SwarmEvent }>;
|
|
19
24
|
onMessage: Event<Message>;
|
|
20
|
-
|
|
21
|
-
getStatus(): SignalStatus[];
|
|
22
|
-
|
|
23
|
-
open(): Promise<void>;
|
|
24
|
-
close(): Promise<void>;
|
|
25
25
|
}
|
|
@@ -13,15 +13,17 @@ import { type Runtime } from '@dxos/protocols/proto/dxos/config';
|
|
|
13
13
|
import { type SwarmEvent } from '@dxos/protocols/proto/dxos/mesh/signal';
|
|
14
14
|
|
|
15
15
|
import { type SignalManager } from './signal-manager';
|
|
16
|
-
import { type CommandTrace, SignalClient
|
|
16
|
+
import { type CommandTrace, SignalClient } from '../signal-client';
|
|
17
|
+
import { type SignalClientMethods, type SignalMethods, type SignalStatus } from '../signal-methods';
|
|
17
18
|
|
|
18
19
|
const MAX_SERVER_FAILURES = 5;
|
|
19
20
|
const WSS_SIGNAL_SERVER_REBOOT_DELAY = 3_000;
|
|
21
|
+
|
|
20
22
|
/**
|
|
21
23
|
* Manages connection to multiple Signal Servers over WebSocket
|
|
22
24
|
*/
|
|
23
25
|
export class WebsocketSignalManager implements SignalManager {
|
|
24
|
-
private readonly _servers = new Map<string,
|
|
26
|
+
private readonly _servers = new Map<string, SignalClientMethods>();
|
|
25
27
|
|
|
26
28
|
private _ctx!: Context;
|
|
27
29
|
private _opened = false;
|
|
@@ -51,12 +53,15 @@ export class WebsocketSignalManager implements SignalManager {
|
|
|
51
53
|
if (this._servers.has(host.server)) {
|
|
52
54
|
continue;
|
|
53
55
|
}
|
|
56
|
+
|
|
57
|
+
// TODO(burdon): Create factory to support different variants.
|
|
54
58
|
const server = new SignalClient(
|
|
55
59
|
host.server,
|
|
56
60
|
async (message) => this.onMessage.emit(message),
|
|
57
61
|
async (data) => this.swarmEvent.emit(data),
|
|
58
62
|
this._getMetadata,
|
|
59
63
|
);
|
|
64
|
+
|
|
60
65
|
server.statusChanged.on(() => this.statusChanged.emit(this.getStatus()));
|
|
61
66
|
|
|
62
67
|
this._servers.set(host.server, server);
|
|
@@ -75,6 +80,7 @@ export class WebsocketSignalManager implements SignalManager {
|
|
|
75
80
|
|
|
76
81
|
this._initContext();
|
|
77
82
|
|
|
83
|
+
// TODO(burdon): Await.
|
|
78
84
|
[...this._servers.values()].forEach((server) => server.open());
|
|
79
85
|
|
|
80
86
|
this._opened = true;
|
|
@@ -94,7 +100,7 @@ export class WebsocketSignalManager implements SignalManager {
|
|
|
94
100
|
}
|
|
95
101
|
|
|
96
102
|
async restartServer(serverName: string) {
|
|
97
|
-
log('
|
|
103
|
+
log('restarting server', { serverName });
|
|
98
104
|
invariant(this._opened, 'server already closed');
|
|
99
105
|
|
|
100
106
|
const server = this._servers.get(serverName);
|
|
@@ -111,7 +117,7 @@ export class WebsocketSignalManager implements SignalManager {
|
|
|
111
117
|
|
|
112
118
|
@synchronized
|
|
113
119
|
async join({ topic, peerId }: { topic: PublicKey; peerId: PublicKey }) {
|
|
114
|
-
log('
|
|
120
|
+
log('join', { topic, peerId });
|
|
115
121
|
invariant(this._opened, 'Closed');
|
|
116
122
|
await this._forEachServer((server) => server.join({ topic, peerId }));
|
|
117
123
|
}
|
|
@@ -133,7 +139,7 @@ export class WebsocketSignalManager implements SignalManager {
|
|
|
133
139
|
recipient: PublicKey;
|
|
134
140
|
payload: Any;
|
|
135
141
|
}): Promise<void> {
|
|
136
|
-
log(
|
|
142
|
+
log('signal', { recipient });
|
|
137
143
|
invariant(this._opened, 'Closed');
|
|
138
144
|
|
|
139
145
|
void this._forEachServer(async (server, serverName) => {
|
|
@@ -155,23 +161,24 @@ export class WebsocketSignalManager implements SignalManager {
|
|
|
155
161
|
async checkServerFailure(serverName: string) {
|
|
156
162
|
const failureCount = this.failureCount.get(serverName!) ?? 0;
|
|
157
163
|
if (failureCount > MAX_SERVER_FAILURES) {
|
|
158
|
-
log.warn(`
|
|
164
|
+
log.warn(`too many failures sending to ${serverName} (${failureCount} > ${MAX_SERVER_FAILURES}), restarting`);
|
|
159
165
|
await this.restartServer(serverName!);
|
|
160
166
|
this.failureCount.set(serverName!, 0);
|
|
161
167
|
return;
|
|
162
168
|
}
|
|
169
|
+
|
|
163
170
|
this.failureCount.set(serverName!, (this.failureCount.get(serverName!) ?? 0) + 1);
|
|
164
171
|
}
|
|
165
172
|
|
|
166
173
|
async subscribeMessages(peerId: PublicKey) {
|
|
167
|
-
log(
|
|
174
|
+
log('subscribed for message stream', { peerId });
|
|
168
175
|
invariant(this._opened, 'Closed');
|
|
169
176
|
|
|
170
177
|
await this._forEachServer(async (server) => server.subscribeMessages(peerId));
|
|
171
178
|
}
|
|
172
179
|
|
|
173
180
|
async unsubscribeMessages(peerId: PublicKey) {
|
|
174
|
-
log(
|
|
181
|
+
log('subscribed for message stream', { peerId });
|
|
175
182
|
invariant(this._opened, 'Closed');
|
|
176
183
|
|
|
177
184
|
await this._forEachServer(async (server) => server.unsubscribeMessages(peerId));
|
|
@@ -184,7 +191,7 @@ export class WebsocketSignalManager implements SignalManager {
|
|
|
184
191
|
}
|
|
185
192
|
|
|
186
193
|
private async _forEachServer<ReturnType>(
|
|
187
|
-
fn: (server:
|
|
194
|
+
fn: (server: SignalMethods, serverName: string) => Promise<ReturnType>,
|
|
188
195
|
): Promise<ReturnType[]> {
|
|
189
196
|
return Promise.all(Array.from(this._servers.entries()).map(([serverName, server]) => fn(server, serverName)));
|
|
190
197
|
}
|
package/src/signal-methods.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { type Any } from '@dxos/codec-protobuf';
|
|
6
6
|
import { type PublicKey } from '@dxos/keys';
|
|
7
|
+
import { type SignalState } from '@dxos/protocols/proto/dxos/mesh/signal';
|
|
7
8
|
|
|
8
9
|
export interface Message {
|
|
9
10
|
author: PublicKey;
|
|
@@ -11,6 +12,18 @@ export interface Message {
|
|
|
11
12
|
payload: Any;
|
|
12
13
|
}
|
|
13
14
|
|
|
15
|
+
export type SignalStatus = {
|
|
16
|
+
host: string;
|
|
17
|
+
state: SignalState;
|
|
18
|
+
error?: string;
|
|
19
|
+
reconnectIn: number;
|
|
20
|
+
connectionStarted: Date;
|
|
21
|
+
lastStateChange: Date;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Message routing interface.
|
|
26
|
+
*/
|
|
14
27
|
export interface SignalMethods {
|
|
15
28
|
/**
|
|
16
29
|
* Join topic on signal network, to be discoverable by other peers.
|
|
@@ -37,3 +50,12 @@ export interface SignalMethods {
|
|
|
37
50
|
*/
|
|
38
51
|
unsubscribeMessages: (peerId: PublicKey) => Promise<void>;
|
|
39
52
|
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Signaling client.
|
|
56
|
+
*/
|
|
57
|
+
export interface SignalClientMethods extends SignalMethods {
|
|
58
|
+
open(): Promise<void>;
|
|
59
|
+
close(): Promise<void>;
|
|
60
|
+
getStatus(): SignalStatus;
|
|
61
|
+
}
|