@dxos/messaging 0.8.4-main.84f28bd → 0.8.4-main.8baae0fced
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/LICENSE +102 -5
- package/dist/lib/neutral/chunk-EC4H56J5.mjs +497 -0
- package/dist/lib/neutral/chunk-EC4H56J5.mjs.map +7 -0
- package/dist/lib/neutral/index.mjs +1249 -0
- package/dist/lib/neutral/index.mjs.map +7 -0
- package/dist/lib/neutral/meta.json +1 -0
- package/dist/lib/{browser → neutral}/testing/index.mjs +13 -12
- package/dist/lib/neutral/testing/index.mjs.map +7 -0
- package/dist/types/src/messenger-monitor.d.ts.map +1 -1
- package/dist/types/src/messenger.blueprint-test.d.ts +1 -1
- package/dist/types/src/messenger.blueprint-test.d.ts.map +1 -1
- package/dist/types/src/messenger.d.ts +4 -3
- package/dist/types/src/messenger.d.ts.map +1 -1
- package/dist/types/src/signal-client/signal-client-monitor.d.ts.map +1 -1
- package/dist/types/src/signal-client/signal-client.d.ts +7 -8
- package/dist/types/src/signal-client/signal-client.d.ts.map +1 -1
- package/dist/types/src/signal-client/signal-local-state.d.ts +1 -1
- package/dist/types/src/signal-client/signal-local-state.d.ts.map +1 -1
- package/dist/types/src/signal-client/signal-rpc-client-monitor.d.ts.map +1 -1
- package/dist/types/src/signal-client/signal-rpc-client.d.ts +3 -3
- package/dist/types/src/signal-client/signal-rpc-client.d.ts.map +1 -1
- package/dist/types/src/signal-manager/edge-signal-manager.d.ts +6 -6
- package/dist/types/src/signal-manager/edge-signal-manager.d.ts.map +1 -1
- package/dist/types/src/signal-manager/index.d.ts +1 -1
- package/dist/types/src/signal-manager/index.d.ts.map +1 -1
- package/dist/types/src/signal-manager/memory-signal-manager.d.ts +6 -5
- package/dist/types/src/signal-manager/memory-signal-manager.d.ts.map +1 -1
- package/dist/types/src/signal-manager/signal-manager.d.ts +1 -1
- package/dist/types/src/signal-manager/signal-manager.d.ts.map +1 -1
- package/dist/types/src/signal-manager/utils.d.ts.map +1 -1
- package/dist/types/src/signal-manager/websocket-signal-manager-monitor.d.ts.map +1 -1
- package/dist/types/src/signal-manager/websocket-signal-manager.d.ts +6 -7
- package/dist/types/src/signal-manager/websocket-signal-manager.d.ts.map +1 -1
- package/dist/types/src/signal-methods.d.ts +7 -7
- package/dist/types/src/signal-methods.d.ts.map +1 -1
- package/dist/types/src/testing/test-builder.d.ts +1 -1
- package/dist/types/src/testing/test-builder.d.ts.map +1 -1
- package/dist/types/src/testing/test-peer.d.ts +1 -1
- package/dist/types/src/testing/test-peer.d.ts.map +1 -1
- package/dist/types/src/testing/utils.d.ts +1 -1
- package/dist/types/src/testing/utils.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +27 -30
- package/src/messenger.blueprint-test.ts +15 -14
- package/src/messenger.node.test.ts +7 -38
- package/src/messenger.ts +38 -33
- package/src/signal-client/signal-client.node.test.ts +12 -11
- package/src/signal-client/signal-client.ts +12 -15
- package/src/signal-client/signal-local-state.ts +3 -3
- package/src/signal-client/signal-rpc-client.node.test.ts +1 -1
- package/src/signal-client/signal-rpc-client.ts +8 -10
- package/src/signal-manager/edge-signal-manager.ts +31 -18
- package/src/signal-manager/index.ts +1 -1
- package/src/signal-manager/memory-signal-manager.ts +18 -15
- package/src/signal-manager/signal-manager.ts +1 -1
- package/src/signal-manager/websocket-signal-manager.node.test.ts +15 -14
- package/src/signal-manager/websocket-signal-manager.ts +12 -18
- package/src/signal-methods.ts +8 -8
- package/src/testing/test-builder.ts +6 -4
- package/src/testing/test-peer.ts +2 -2
- package/src/testing/utils.ts +2 -2
- package/dist/lib/browser/chunk-PXN7MXD6.mjs +0 -2309
- package/dist/lib/browser/chunk-PXN7MXD6.mjs.map +0 -7
- package/dist/lib/browser/index.mjs +0 -22
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/browser/testing/index.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-GJW3QPXP.mjs +0 -2309
- package/dist/lib/node-esm/chunk-GJW3QPXP.mjs.map +0 -7
- package/dist/lib/node-esm/index.mjs +0 -22
- 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 -143
- package/dist/lib/node-esm/testing/index.mjs.map +0 -7
|
@@ -4,16 +4,15 @@
|
|
|
4
4
|
|
|
5
5
|
import WebSocket from 'isomorphic-ws';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { TimeoutError, Trigger, scheduleTaskInterval } from '@dxos/async';
|
|
8
8
|
import { type Any, type Stream } from '@dxos/codec-protobuf';
|
|
9
9
|
import { Context } from '@dxos/context';
|
|
10
10
|
import { invariant } from '@dxos/invariant';
|
|
11
11
|
import { PublicKey } from '@dxos/keys';
|
|
12
12
|
import { log } from '@dxos/log';
|
|
13
|
-
import { trace } from '@dxos/protocols';
|
|
14
13
|
import { schema } from '@dxos/protocols/proto';
|
|
15
|
-
import { type Message as SignalMessage
|
|
16
|
-
import {
|
|
14
|
+
import { type Signal, type Message as SignalMessage } from '@dxos/protocols/proto/dxos/mesh/signal';
|
|
15
|
+
import { type ProtoRpcPeer, createProtoRpcPeer } from '@dxos/rpc';
|
|
17
16
|
|
|
18
17
|
import { SignalRpcClientMonitor } from './signal-rpc-client-monitor';
|
|
19
18
|
|
|
@@ -36,7 +35,7 @@ export type SignalCallbacks = {
|
|
|
36
35
|
getMetadata?: () => any;
|
|
37
36
|
};
|
|
38
37
|
|
|
39
|
-
export type
|
|
38
|
+
export type SignalRPCClientProps = {
|
|
40
39
|
url: string;
|
|
41
40
|
callbacks?: SignalCallbacks;
|
|
42
41
|
};
|
|
@@ -61,9 +60,8 @@ export class SignalRPCClient {
|
|
|
61
60
|
|
|
62
61
|
private readonly _monitor = new SignalRpcClientMonitor();
|
|
63
62
|
|
|
64
|
-
constructor({ url, callbacks = {} }:
|
|
65
|
-
|
|
66
|
-
log.trace('dxos.mesh.signal-rpc-client.constructor', trace.begin({ id: traceId }));
|
|
63
|
+
constructor({ url, callbacks = {} }: SignalRPCClientProps) {
|
|
64
|
+
log('creating signal rpc client', { url });
|
|
67
65
|
this._url = url;
|
|
68
66
|
this._callbacks = callbacks;
|
|
69
67
|
this._socket = new WebSocket(this._url);
|
|
@@ -149,7 +147,7 @@ export class SignalRPCClient {
|
|
|
149
147
|
log.warn(`Socket ${event.type ?? 'unknown'} error`, { message: event.message, url: this._url });
|
|
150
148
|
};
|
|
151
149
|
|
|
152
|
-
log
|
|
150
|
+
log('created signal rpc client', { url });
|
|
153
151
|
}
|
|
154
152
|
|
|
155
153
|
async close(): Promise<void> {
|
|
@@ -169,7 +167,7 @@ export class SignalRPCClient {
|
|
|
169
167
|
|
|
170
168
|
await this._closeComplete.wait({ timeout: 1_000 });
|
|
171
169
|
} catch (err) {
|
|
172
|
-
const failureReason = err instanceof TimeoutError ? 'timeout' : err?.constructor?.name ?? 'unknown';
|
|
170
|
+
const failureReason = err instanceof TimeoutError ? 'timeout' : (err?.constructor?.name ?? 'unknown');
|
|
173
171
|
this._monitor.recordClientCloseFailure({ failureReason });
|
|
174
172
|
}
|
|
175
173
|
}
|
|
@@ -3,25 +3,25 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { Event, scheduleMicroTask } from '@dxos/async';
|
|
6
|
-
import {
|
|
7
|
-
import { type EdgeConnection, protocol } from '@dxos/edge-client';
|
|
6
|
+
import { type Context, Resource, cancelWithContext } from '@dxos/context';
|
|
7
|
+
import { type EdgeConnection, EdgeIdentityChangedError, protocol } from '@dxos/edge-client';
|
|
8
8
|
import { invariant } from '@dxos/invariant';
|
|
9
9
|
import { PublicKey } from '@dxos/keys';
|
|
10
10
|
import { log } from '@dxos/log';
|
|
11
11
|
import { EdgeService } from '@dxos/protocols';
|
|
12
12
|
import { type buf, bufWkt } from '@dxos/protocols/buf';
|
|
13
13
|
import {
|
|
14
|
-
SwarmRequestSchema,
|
|
15
|
-
SwarmRequest_Action as SwarmRequestAction,
|
|
16
|
-
SwarmResponseSchema,
|
|
17
14
|
type Message as EdgeMessage,
|
|
18
15
|
type PeerSchema,
|
|
16
|
+
SwarmRequest_Action as SwarmRequestAction,
|
|
17
|
+
SwarmRequestSchema,
|
|
18
|
+
SwarmResponseSchema,
|
|
19
19
|
} from '@dxos/protocols/buf/dxos/edge/messenger_pb';
|
|
20
20
|
import { type SwarmResponse } from '@dxos/protocols/proto/dxos/edge/messenger';
|
|
21
21
|
import { ComplexMap, ComplexSet } from '@dxos/util';
|
|
22
22
|
|
|
23
|
+
import { type Message, type PeerInfo, PeerInfoHash, type SwarmEvent } from '../signal-methods';
|
|
23
24
|
import { type SignalManager } from './signal-manager';
|
|
24
|
-
import { type PeerInfo, type Message, type SwarmEvent, PeerInfoHash } from '../signal-methods';
|
|
25
25
|
|
|
26
26
|
export class EdgeSignalManager extends Resource implements SignalManager {
|
|
27
27
|
/**
|
|
@@ -59,7 +59,7 @@ export class EdgeSignalManager extends Resource implements SignalManager {
|
|
|
59
59
|
/**
|
|
60
60
|
* Warning: PeerInfo is inferred from edgeConnection.
|
|
61
61
|
*/
|
|
62
|
-
async join({ topic, peer }: { topic: PublicKey; peer: PeerInfo }): Promise<void> {
|
|
62
|
+
async join(ctx: Context, { topic, peer }: { topic: PublicKey; peer: PeerInfo }): Promise<void> {
|
|
63
63
|
if (!this._matchSelfPeerInfo(peer)) {
|
|
64
64
|
// NOTE: Could only join swarm with the same peer info as the edge connection.
|
|
65
65
|
log.warn('ignoring peer info on join request', {
|
|
@@ -76,6 +76,7 @@ export class EdgeSignalManager extends Resource implements SignalManager {
|
|
|
76
76
|
|
|
77
77
|
this._swarmPeers.set(topic, { lastState: peer.state, joinedPeers: new ComplexSet<PeerInfo>(PeerInfoHash) });
|
|
78
78
|
await this._edgeConnection.send(
|
|
79
|
+
ctx,
|
|
79
80
|
protocol.createMessage(SwarmRequestSchema, {
|
|
80
81
|
serviceId: EdgeService.SWARM,
|
|
81
82
|
source: createMessageSource(topic, peer),
|
|
@@ -84,24 +85,35 @@ export class EdgeSignalManager extends Resource implements SignalManager {
|
|
|
84
85
|
);
|
|
85
86
|
}
|
|
86
87
|
|
|
87
|
-
async leave({ topic, peer }: { topic: PublicKey; peer: PeerInfo }): Promise<void> {
|
|
88
|
+
async leave(ctx: Context, { topic, peer }: { topic: PublicKey; peer: PeerInfo }): Promise<void> {
|
|
88
89
|
this._swarmPeers.delete(topic);
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
90
|
+
try {
|
|
91
|
+
await this._edgeConnection.send(
|
|
92
|
+
ctx,
|
|
93
|
+
protocol.createMessage(SwarmRequestSchema, {
|
|
94
|
+
serviceId: EdgeService.SWARM,
|
|
95
|
+
source: createMessageSource(topic, peer),
|
|
96
|
+
payload: { action: SwarmRequestAction.LEAVE, swarmKeys: [topic.toHex()] },
|
|
97
|
+
}),
|
|
98
|
+
);
|
|
99
|
+
} catch (err) {
|
|
100
|
+
if (err instanceof EdgeIdentityChangedError) {
|
|
101
|
+
// Note: On edge identity change, the connection is closed and EDGE will remove us from the swarm.
|
|
102
|
+
// So we should just delete the swarm from _swarmPeers.
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
throw err;
|
|
106
|
+
}
|
|
96
107
|
}
|
|
97
108
|
|
|
98
|
-
async query({ topic }: { topic: PublicKey }): Promise<SwarmResponse> {
|
|
109
|
+
async query(ctx: Context, { topic }: { topic: PublicKey }): Promise<SwarmResponse> {
|
|
99
110
|
const response = cancelWithContext(
|
|
100
111
|
this._ctx,
|
|
101
112
|
this.swarmState.waitFor((state) => state.swarmKey === topic.toHex()),
|
|
102
113
|
);
|
|
103
114
|
|
|
104
115
|
await this._edgeConnection.send(
|
|
116
|
+
ctx,
|
|
105
117
|
protocol.createMessage(SwarmRequestSchema, {
|
|
106
118
|
serviceId: EdgeService.SWARM,
|
|
107
119
|
source: createMessageSource(topic, {
|
|
@@ -115,7 +127,7 @@ export class EdgeSignalManager extends Resource implements SignalManager {
|
|
|
115
127
|
return response;
|
|
116
128
|
}
|
|
117
129
|
|
|
118
|
-
async sendMessage(message: Message): Promise<void> {
|
|
130
|
+
async sendMessage(ctx: Context, message: Message): Promise<void> {
|
|
119
131
|
if (!this._matchSelfPeerInfo(message.author)) {
|
|
120
132
|
// NOTE: Could only join swarm with the same peer info as the edge connection.
|
|
121
133
|
log.warn('ignoring author on send request', {
|
|
@@ -125,6 +137,7 @@ export class EdgeSignalManager extends Resource implements SignalManager {
|
|
|
125
137
|
}
|
|
126
138
|
|
|
127
139
|
await this._edgeConnection.send(
|
|
140
|
+
ctx,
|
|
128
141
|
protocol.createMessage(bufWkt.AnySchema, {
|
|
129
142
|
serviceId: EdgeService.SIGNAL,
|
|
130
143
|
source: message.author,
|
|
@@ -218,7 +231,7 @@ export class EdgeSignalManager extends Resource implements SignalManager {
|
|
|
218
231
|
private async _rejoinAllSwarms(): Promise<void> {
|
|
219
232
|
log('rejoin swarms', { swarms: Array.from(this._swarmPeers.keys()) });
|
|
220
233
|
for (const [topic, { lastState }] of this._swarmPeers.entries()) {
|
|
221
|
-
await this.join({
|
|
234
|
+
await this.join(this._ctx, {
|
|
222
235
|
topic,
|
|
223
236
|
peer: {
|
|
224
237
|
peerKey: this._edgeConnection.peerKey,
|
|
@@ -13,8 +13,8 @@ import { type SwarmResponse } from '@dxos/protocols/proto/dxos/edge/messenger';
|
|
|
13
13
|
import { type QueryRequest } from '@dxos/protocols/proto/dxos/edge/signal';
|
|
14
14
|
import { ComplexMap, ComplexSet } from '@dxos/util';
|
|
15
15
|
|
|
16
|
+
import { type Message, type PeerInfo, PeerInfoHash, type SignalStatus, type SwarmEvent } from '../signal-methods';
|
|
16
17
|
import { type SignalManager } from './signal-manager';
|
|
17
|
-
import { type SwarmEvent, type PeerInfo, type SignalStatus, type Message, PeerInfoHash } from '../signal-methods';
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Common signaling context that connects multiple MemorySignalManager instances.
|
|
@@ -62,7 +62,7 @@ export class MemorySignalManager implements SignalManager {
|
|
|
62
62
|
this._ctx = new Context();
|
|
63
63
|
this._ctx.onDispose(this._context.swarmEvent.on((data) => this.swarmEvent.emit(data)));
|
|
64
64
|
|
|
65
|
-
await Promise.all([...this._joinedSwarms.values()].map((value) => this.join(value)));
|
|
65
|
+
await Promise.all([...this._joinedSwarms.values()].map((value) => this.join(this._ctx, value)));
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
async close(): Promise<void> {
|
|
@@ -75,7 +75,7 @@ export class MemorySignalManager implements SignalManager {
|
|
|
75
75
|
[...this._joinedSwarms.values()],
|
|
76
76
|
);
|
|
77
77
|
|
|
78
|
-
await Promise.all([...this._joinedSwarms.values()].map((value) => this.leave(value)));
|
|
78
|
+
await Promise.all([...this._joinedSwarms.values()].map((value) => this.leave(this._ctx, value)));
|
|
79
79
|
|
|
80
80
|
// assign joined swarms back because .leave() deletes it.
|
|
81
81
|
this._joinedSwarms = joinedSwarmsCopy;
|
|
@@ -87,7 +87,7 @@ export class MemorySignalManager implements SignalManager {
|
|
|
87
87
|
return [];
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
async join({ topic, peer }: { topic: PublicKey; peer: PeerInfo }): Promise<void> {
|
|
90
|
+
async join(_ctx: Context, { topic, peer }: { topic: PublicKey; peer: PeerInfo }): Promise<void> {
|
|
91
91
|
invariant(!this._ctx.disposed, 'Closed');
|
|
92
92
|
|
|
93
93
|
this._joinedSwarms.add({ topic, peer });
|
|
@@ -119,7 +119,7 @@ export class MemorySignalManager implements SignalManager {
|
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
async leave({ topic, peer }: { topic: PublicKey; peer: PeerInfo }): Promise<void> {
|
|
122
|
+
async leave(_ctx: Context, { topic, peer }: { topic: PublicKey; peer: PeerInfo }): Promise<void> {
|
|
123
123
|
invariant(!this._ctx.disposed, 'Closed');
|
|
124
124
|
|
|
125
125
|
this._joinedSwarms.delete({ topic, peer });
|
|
@@ -140,19 +140,22 @@ export class MemorySignalManager implements SignalManager {
|
|
|
140
140
|
this._context.swarmEvent.emit(swarmEvent);
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
-
async query(request: QueryRequest): Promise<SwarmResponse> {
|
|
143
|
+
async query(_ctx: Context, request: QueryRequest): Promise<SwarmResponse> {
|
|
144
144
|
throw new Error('Not implemented');
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
async sendMessage(
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
147
|
+
async sendMessage(
|
|
148
|
+
_ctx: Context,
|
|
149
|
+
{
|
|
150
|
+
author,
|
|
151
|
+
recipient,
|
|
152
|
+
payload,
|
|
153
|
+
}: {
|
|
154
|
+
author: PeerInfo;
|
|
155
|
+
recipient: PeerInfo;
|
|
156
|
+
payload: Any;
|
|
157
|
+
},
|
|
158
|
+
): Promise<void> {
|
|
156
159
|
log('send message', { author, recipient, ...dec(payload) });
|
|
157
160
|
|
|
158
161
|
invariant(recipient);
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { type Event } from '@dxos/async';
|
|
6
6
|
import { type Lifecycle } from '@dxos/context';
|
|
7
7
|
|
|
8
|
-
import { type
|
|
8
|
+
import { type SignalMethods, type SignalStatus } from '../signal-methods';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Manages a collection of signaling clients.
|
|
@@ -5,12 +5,13 @@
|
|
|
5
5
|
import { afterAll, beforeAll, describe, test } from 'vitest';
|
|
6
6
|
|
|
7
7
|
import { asyncTimeout, sleep } from '@dxos/async';
|
|
8
|
+
import { Context } from '@dxos/context';
|
|
8
9
|
import { PublicKey } from '@dxos/keys';
|
|
9
|
-
import {
|
|
10
|
+
import { type SignalServerRunner, runTestSignalServer } from '@dxos/signal';
|
|
10
11
|
import { openAndClose } from '@dxos/test-utils';
|
|
11
12
|
|
|
12
|
-
import { WebsocketSignalManager } from './websocket-signal-manager';
|
|
13
13
|
import { createMessage, expectPeerAvailable, expectReceivedMessage } from '../testing';
|
|
14
|
+
import { WebsocketSignalManager } from './websocket-signal-manager';
|
|
14
15
|
|
|
15
16
|
describe.skip('WebSocketSignalManager', () => {
|
|
16
17
|
let broker1: SignalServerRunner;
|
|
@@ -39,9 +40,9 @@ describe.skip('WebSocketSignalManager', () => {
|
|
|
39
40
|
const joined21 = expectPeerAvailable(client2, topic, { peerKey: peer1.toHex() });
|
|
40
41
|
const joined31 = expectPeerAvailable(client3, topic, { peerKey: peer1.toHex() });
|
|
41
42
|
|
|
42
|
-
await client1.join({ topic, peer: { peerKey: peer1.toHex() } });
|
|
43
|
-
await client2.join({ topic, peer: { peerKey: peer2.toHex() } });
|
|
44
|
-
await client3.join({ topic, peer: { peerKey: peer3.toHex() } });
|
|
43
|
+
await client1.join(Context.default(), { topic, peer: { peerKey: peer1.toHex() } });
|
|
44
|
+
await client2.join(Context.default(), { topic, peer: { peerKey: peer2.toHex() } });
|
|
45
|
+
await client3.join(Context.default(), { topic, peer: { peerKey: peer3.toHex() } });
|
|
45
46
|
|
|
46
47
|
await Promise.all([joined12, joined13, joined21, joined31]);
|
|
47
48
|
});
|
|
@@ -56,8 +57,8 @@ describe.skip('WebSocketSignalManager', () => {
|
|
|
56
57
|
const joined12 = expectPeerAvailable(client1, topic, { peerKey: peer2.toHex() });
|
|
57
58
|
const joined21 = expectPeerAvailable(client2, topic, { peerKey: peer1.toHex() });
|
|
58
59
|
|
|
59
|
-
await client1.join({ topic, peer: { peerKey: peer1.toHex() } });
|
|
60
|
-
await client2.join({ topic, peer: { peerKey: peer2.toHex() } });
|
|
60
|
+
await client1.join(Context.default(), { topic, peer: { peerKey: peer1.toHex() } });
|
|
61
|
+
await client2.join(Context.default(), { topic, peer: { peerKey: peer2.toHex() } });
|
|
61
62
|
|
|
62
63
|
await asyncTimeout(Promise.all([joined12, joined21]), 1_000);
|
|
63
64
|
|
|
@@ -66,7 +67,7 @@ describe.skip('WebSocketSignalManager', () => {
|
|
|
66
67
|
const received = expectReceivedMessage(client2.onMessage, message);
|
|
67
68
|
await client2.subscribeMessages({ peerKey: peer2.toHex() });
|
|
68
69
|
await sleep(50);
|
|
69
|
-
await client1.sendMessage(message);
|
|
70
|
+
await client1.sendMessage(Context.default(), message);
|
|
70
71
|
|
|
71
72
|
await asyncTimeout(received, 1_000);
|
|
72
73
|
});
|
|
@@ -81,8 +82,8 @@ describe.skip('WebSocketSignalManager', () => {
|
|
|
81
82
|
const joined12 = expectPeerAvailable(client1, topic, { peerKey: peer2.toHex() });
|
|
82
83
|
const joined21 = expectPeerAvailable(client2, topic, { peerKey: peer1.toHex() });
|
|
83
84
|
|
|
84
|
-
await client1.join({ topic, peer: { peerKey: peer1.toHex() } });
|
|
85
|
-
await client2.join({ topic, peer: { peerKey: peer2.toHex() } });
|
|
85
|
+
await client1.join(Context.default(), { topic, peer: { peerKey: peer1.toHex() } });
|
|
86
|
+
await client2.join(Context.default(), { topic, peer: { peerKey: peer2.toHex() } });
|
|
86
87
|
|
|
87
88
|
await Promise.all([joined12, joined21]);
|
|
88
89
|
});
|
|
@@ -97,15 +98,15 @@ describe.skip('WebSocketSignalManager', () => {
|
|
|
97
98
|
const joined112 = expectPeerAvailable(client1, topic1, { peerKey: peer2.toHex() });
|
|
98
99
|
const joined121 = expectPeerAvailable(client2, topic1, { peerKey: peer1.toHex() });
|
|
99
100
|
|
|
100
|
-
await client1.join({ topic: topic1, peer: { peerKey: peer1.toHex() } });
|
|
101
|
-
await client2.join({ topic: topic1, peer: { peerKey: peer2.toHex() } });
|
|
101
|
+
await client1.join(Context.default(), { topic: topic1, peer: { peerKey: peer1.toHex() } });
|
|
102
|
+
await client2.join(Context.default(), { topic: topic1, peer: { peerKey: peer2.toHex() } });
|
|
102
103
|
await Promise.all([joined112, joined121]);
|
|
103
104
|
|
|
104
105
|
const joined212 = expectPeerAvailable(client1, topic2, { peerKey: peer2.toHex() });
|
|
105
106
|
const joined221 = expectPeerAvailable(client2, topic2, { peerKey: peer1.toHex() });
|
|
106
107
|
|
|
107
|
-
await client1.join({ topic: topic2, peer: { peerKey: peer1.toHex() } });
|
|
108
|
-
await client2.join({ topic: topic2, peer: { peerKey: peer2.toHex() } });
|
|
108
|
+
await client1.join(Context.default(), { topic: topic2, peer: { peerKey: peer1.toHex() } });
|
|
109
|
+
await client2.join(Context.default(), { topic: topic2, peer: { peerKey: peer2.toHex() } });
|
|
109
110
|
await Promise.all([joined212, joined221]);
|
|
110
111
|
});
|
|
111
112
|
});
|
|
@@ -3,27 +3,26 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { Event, sleep, synchronized } from '@dxos/async';
|
|
6
|
-
import { LifecycleState, Resource } from '@dxos/context';
|
|
6
|
+
import { type Context, LifecycleState, Resource } from '@dxos/context';
|
|
7
7
|
import { invariant } from '@dxos/invariant';
|
|
8
|
-
import { PublicKey } from '@dxos/keys';
|
|
9
8
|
import { log } from '@dxos/log';
|
|
10
|
-
import { RateLimitExceededError, TimeoutError
|
|
9
|
+
import { RateLimitExceededError, TimeoutError } from '@dxos/protocols';
|
|
11
10
|
import { type Runtime } from '@dxos/protocols/proto/dxos/config';
|
|
12
11
|
import { type SwarmResponse } from '@dxos/protocols/proto/dxos/edge/messenger';
|
|
13
12
|
import { type JoinRequest, type LeaveRequest, type QueryRequest } from '@dxos/protocols/proto/dxos/edge/signal';
|
|
14
13
|
import { BitField, safeAwaitAll } from '@dxos/util';
|
|
15
14
|
|
|
16
|
-
import { type SignalManager } from './signal-manager';
|
|
17
|
-
import { WebsocketSignalManagerMonitor } from './websocket-signal-manager-monitor';
|
|
18
15
|
import { SignalClient } from '../signal-client';
|
|
19
16
|
import {
|
|
20
|
-
type PeerInfo,
|
|
21
17
|
type Message,
|
|
18
|
+
type PeerInfo,
|
|
22
19
|
type SignalClientMethods,
|
|
23
20
|
type SignalMethods,
|
|
24
21
|
type SignalStatus,
|
|
25
22
|
type SwarmEvent,
|
|
26
23
|
} from '../signal-methods';
|
|
24
|
+
import { type SignalManager } from './signal-manager';
|
|
25
|
+
import { WebsocketSignalManagerMonitor } from './websocket-signal-manager-monitor';
|
|
27
26
|
|
|
28
27
|
const MAX_SERVER_FAILURES = 5;
|
|
29
28
|
const WSS_SIGNAL_SERVER_REBOOT_DELAY = 3_000;
|
|
@@ -48,8 +47,6 @@ export class WebsocketSignalManager extends Resource implements SignalManager {
|
|
|
48
47
|
|
|
49
48
|
readonly onMessage = new Event<Message>();
|
|
50
49
|
|
|
51
|
-
private readonly _instanceId = PublicKey.random().toHex();
|
|
52
|
-
|
|
53
50
|
constructor(
|
|
54
51
|
private readonly _hosts: Runtime.Services.Signal[],
|
|
55
52
|
private readonly _getMetadata?: () => any,
|
|
@@ -76,11 +73,8 @@ export class WebsocketSignalManager extends Resource implements SignalManager {
|
|
|
76
73
|
|
|
77
74
|
protected override async _open(): Promise<void> {
|
|
78
75
|
log('open signal manager', { hosts: this._hosts });
|
|
79
|
-
log.trace('dxos.mesh.websocket-signal-manager.open', trace.begin({ id: this._instanceId }));
|
|
80
76
|
|
|
81
77
|
await safeAwaitAll(this._servers.values(), (server) => server.open());
|
|
82
|
-
|
|
83
|
-
log.trace('dxos.mesh.websocket-signal-manager.open', trace.end({ id: this._instanceId }));
|
|
84
78
|
}
|
|
85
79
|
|
|
86
80
|
protected override async _close(): Promise<void> {
|
|
@@ -104,30 +98,30 @@ export class WebsocketSignalManager extends Resource implements SignalManager {
|
|
|
104
98
|
}
|
|
105
99
|
|
|
106
100
|
@synchronized
|
|
107
|
-
async join({ topic, peer }: JoinRequest): Promise<void> {
|
|
101
|
+
async join(_ctx: Context, { topic, peer }: JoinRequest): Promise<void> {
|
|
108
102
|
log('join', { topic, peer });
|
|
109
103
|
invariant(this._lifecycleState === LifecycleState.OPEN);
|
|
110
|
-
await this._forEachServer((server) => server.join({ topic, peer }));
|
|
104
|
+
await this._forEachServer((server) => server.join(_ctx, { topic, peer }));
|
|
111
105
|
}
|
|
112
106
|
|
|
113
107
|
@synchronized
|
|
114
|
-
async leave({ topic, peer }: LeaveRequest): Promise<void> {
|
|
108
|
+
async leave(_ctx: Context, { topic, peer }: LeaveRequest): Promise<void> {
|
|
115
109
|
log('leaving', { topic, peer });
|
|
116
110
|
invariant(this._lifecycleState === LifecycleState.OPEN);
|
|
117
|
-
await this._forEachServer((server) => server.leave({ topic, peer }));
|
|
111
|
+
await this._forEachServer((server) => server.leave(_ctx, { topic, peer }));
|
|
118
112
|
}
|
|
119
113
|
|
|
120
|
-
async query({ topic }: QueryRequest): Promise<SwarmResponse> {
|
|
114
|
+
async query(_ctx: Context, { topic }: QueryRequest): Promise<SwarmResponse> {
|
|
121
115
|
throw new Error('Not implemented');
|
|
122
116
|
}
|
|
123
117
|
|
|
124
|
-
async sendMessage({ author, recipient, payload }: Message): Promise<void> {
|
|
118
|
+
async sendMessage(_ctx: Context, { author, recipient, payload }: Message): Promise<void> {
|
|
125
119
|
log('signal', { recipient });
|
|
126
120
|
invariant(this._lifecycleState === LifecycleState.OPEN);
|
|
127
121
|
|
|
128
122
|
void this._forEachServer(async (server, serverName, index) => {
|
|
129
123
|
void server
|
|
130
|
-
.sendMessage({ author, recipient, payload })
|
|
124
|
+
.sendMessage(_ctx, { author, recipient, payload })
|
|
131
125
|
.then(() => this._clearServerFailedFlag(serverName, index))
|
|
132
126
|
.catch((err) => {
|
|
133
127
|
if (err instanceof RateLimitExceededError) {
|
package/src/signal-methods.ts
CHANGED
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { type Event } from '@dxos/async';
|
|
6
|
-
import { type Lifecycle } from '@dxos/context';
|
|
7
|
-
import { type
|
|
6
|
+
import { type Context, type Lifecycle } from '@dxos/context';
|
|
7
|
+
import { type Peer, type SwarmResponse } from '@dxos/protocols/proto/dxos/edge/messenger';
|
|
8
8
|
import {
|
|
9
|
+
type JoinRequest,
|
|
9
10
|
type LeaveRequest,
|
|
10
11
|
type Message,
|
|
11
|
-
type SwarmEvent,
|
|
12
|
-
type JoinRequest,
|
|
13
12
|
type QueryRequest,
|
|
13
|
+
type SwarmEvent,
|
|
14
14
|
} from '@dxos/protocols/proto/dxos/edge/signal';
|
|
15
15
|
import { type SignalState } from '@dxos/protocols/proto/dxos/mesh/signal';
|
|
16
16
|
|
|
@@ -51,22 +51,22 @@ export interface SignalMethods {
|
|
|
51
51
|
/**
|
|
52
52
|
* Join topic on signal network, to be discoverable by other peers.
|
|
53
53
|
*/
|
|
54
|
-
join: (params: JoinRequest) => Promise<void>;
|
|
54
|
+
join: (ctx: Context, params: JoinRequest) => Promise<void>;
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
57
|
* Leave topic on signal network, to stop being discoverable by other peers.
|
|
58
58
|
*/
|
|
59
|
-
leave: (params: LeaveRequest) => Promise<void>;
|
|
59
|
+
leave: (ctx: Context, params: LeaveRequest) => Promise<void>;
|
|
60
60
|
|
|
61
61
|
/**
|
|
62
62
|
* Query peers in the swarm without joining it.
|
|
63
63
|
*/
|
|
64
|
-
query: (params: QueryRequest) => Promise<SwarmResponse>;
|
|
64
|
+
query: (ctx: Context, params: QueryRequest) => Promise<SwarmResponse>;
|
|
65
65
|
|
|
66
66
|
/**
|
|
67
67
|
* Send message to peer.
|
|
68
68
|
*/
|
|
69
|
-
sendMessage: (message: Message) => Promise<void>;
|
|
69
|
+
sendMessage: (ctx: Context, message: Message) => Promise<void>;
|
|
70
70
|
|
|
71
71
|
/**
|
|
72
72
|
* Start receiving messages from peer.
|
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
|
|
5
|
+
import { type Context } from '@dxos/context';
|
|
6
|
+
|
|
7
|
+
import { MemorySignalManager, MemorySignalManagerContext, type SignalManager } from '../signal-manager';
|
|
7
8
|
import { type Message } from '../signal-methods';
|
|
9
|
+
import { TestPeer } from './test-peer';
|
|
8
10
|
|
|
9
11
|
export type TestBuilderOptions = {
|
|
10
12
|
signalManagerFactory?: (peer: TestPeer) => Promise<SignalManager>;
|
|
@@ -24,9 +26,9 @@ export class TestBuilder {
|
|
|
24
26
|
if (this.options.messageDisruption) {
|
|
25
27
|
// Imitates signal network disruptions (e. g. message doubling, ).
|
|
26
28
|
const trueSend = signalManager.sendMessage.bind(signalManager);
|
|
27
|
-
signalManager.sendMessage = async (message: Message) => {
|
|
29
|
+
signalManager.sendMessage = async (ctx: Context, message: Message) => {
|
|
28
30
|
for (const msg of this.options.messageDisruption!(message)) {
|
|
29
|
-
await trueSend(msg);
|
|
31
|
+
await trueSend(ctx, msg);
|
|
30
32
|
}
|
|
31
33
|
};
|
|
32
34
|
}
|
package/src/testing/test-peer.ts
CHANGED
|
@@ -9,11 +9,11 @@ import { PublicKey } from '@dxos/keys';
|
|
|
9
9
|
import { log } from '@dxos/log';
|
|
10
10
|
import { buf } from '@dxos/protocols/buf';
|
|
11
11
|
|
|
12
|
-
import { type TestBuilder } from './test-builder';
|
|
13
|
-
import { expectPeerAvailable, expectPeerLeft, expectReceivedMessage } from './utils';
|
|
14
12
|
import { Messenger } from '../messenger';
|
|
15
13
|
import { type SignalManager } from '../signal-manager';
|
|
16
14
|
import { type Message, type PeerInfo } from '../signal-methods';
|
|
15
|
+
import { type TestBuilder } from './test-builder';
|
|
16
|
+
import { expectPeerAvailable, expectPeerLeft, expectReceivedMessage } from './utils';
|
|
17
17
|
|
|
18
18
|
export class TestPeer extends Resource {
|
|
19
19
|
public peerId = PublicKey.random();
|
package/src/testing/utils.ts
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { type Event, asyncTimeout } from '@dxos/async';
|
|
6
6
|
import { type Any } from '@dxos/codec-protobuf';
|
|
7
7
|
import { PublicKey } from '@dxos/keys';
|
|
8
8
|
|
|
9
|
+
import { type Message, type PeerInfo, type SignalMethods } from '../signal-methods';
|
|
9
10
|
import { PAYLOAD_1 } from './test-messages';
|
|
10
|
-
import { type SignalMethods, type Message, type PeerInfo } from '../signal-methods';
|
|
11
11
|
|
|
12
12
|
export const expectPeerAvailable = (client: SignalMethods, expectedTopic: PublicKey, peer: PeerInfo) =>
|
|
13
13
|
asyncTimeout(
|