@dxos/messaging 0.6.8-main.3be982f → 0.6.8-staging.77f93a3
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 +466 -199
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +456 -197
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/types/src/messenger.blueprint-test.d.ts +4 -0
- package/dist/types/src/messenger.blueprint-test.d.ts.map +1 -0
- package/dist/types/src/messenger.d.ts +4 -10
- package/dist/types/src/messenger.d.ts.map +1 -1
- package/dist/types/src/signal-client/signal-client.d.ts +6 -10
- package/dist/types/src/signal-client/signal-client.d.ts.map +1 -1
- package/dist/types/src/signal-client/signal-local-state.d.ts +2 -10
- package/dist/types/src/signal-client/signal-local-state.d.ts.map +1 -1
- package/dist/types/src/signal-manager/edge-signal-manager.d.ts +18 -19
- package/dist/types/src/signal-manager/edge-signal-manager.d.ts.map +1 -1
- package/dist/types/src/signal-manager/index.d.ts +1 -0
- package/dist/types/src/signal-manager/index.d.ts.map +1 -1
- package/dist/types/src/signal-manager/memory-signal-manager.d.ts +14 -25
- package/dist/types/src/signal-manager/memory-signal-manager.d.ts.map +1 -1
- package/dist/types/src/signal-manager/signal-manager.d.ts +5 -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 +14 -29
- package/dist/types/src/signal-manager/websocket-signal-manager.d.ts.map +1 -1
- package/dist/types/src/signal-methods.d.ts +29 -14
- package/dist/types/src/signal-methods.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +5 -0
- package/dist/types/src/testing/index.d.ts.map +1 -0
- package/dist/types/src/testing/test-builder.d.ts +19 -0
- package/dist/types/src/testing/test-builder.d.ts.map +1 -0
- package/dist/types/src/testing/test-messages.d.ts +6 -0
- package/dist/types/src/testing/test-messages.d.ts.map +1 -0
- package/dist/types/src/testing/test-peer.d.ts +23 -0
- package/dist/types/src/testing/test-peer.d.ts.map +1 -0
- package/dist/types/src/testing/utils.d.ts +10 -0
- package/dist/types/src/testing/utils.d.ts.map +1 -0
- package/package.json +15 -14
- package/src/messenger.blueprint-test.ts +346 -0
- package/src/messenger.test.ts +26 -362
- package/src/messenger.ts +20 -18
- package/src/signal-client/signal-client-monitor.ts +3 -3
- package/src/signal-client/signal-client.test.ts +56 -52
- package/src/signal-client/signal-client.ts +30 -16
- package/src/signal-client/signal-local-state.ts +28 -10
- package/src/signal-manager/edge-signal-manager.test.ts +31 -35
- package/src/signal-manager/edge-signal-manager.ts +88 -36
- package/src/signal-manager/index.ts +1 -0
- package/src/signal-manager/memory-signal-manager.ts +36 -50
- package/src/signal-manager/signal-manager.ts +5 -7
- package/src/signal-manager/websocket-signal-manager.test.ts +27 -31
- package/src/signal-manager/websocket-signal-manager.ts +34 -65
- package/src/signal-methods.ts +33 -11
- package/src/testing/index.ts +8 -0
- package/src/testing/test-builder.ts +54 -0
- package/src/testing/test-messages.ts +24 -0
- package/src/testing/test-peer.ts +66 -0
- package/src/testing/utils.ts +50 -0
- package/dist/types/src/testing.d.ts +0 -40
- package/dist/types/src/testing.d.ts.map +0 -1
- package/src/testing.ts +0 -120
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
6
6
|
import { expect } from 'earljs';
|
|
7
7
|
|
|
8
|
-
import {
|
|
9
|
-
import { type TaggedType } from '@dxos/codec-protobuf';
|
|
8
|
+
import { asyncTimeout, waitForCondition } from '@dxos/async';
|
|
9
|
+
import { type Any, type TaggedType } from '@dxos/codec-protobuf';
|
|
10
10
|
import { PublicKey } from '@dxos/keys';
|
|
11
11
|
import { type TYPES } from '@dxos/protocols';
|
|
12
12
|
import { runTestSignalServer, type SignalServerRunner } from '@dxos/signal';
|
|
@@ -14,10 +14,11 @@ import { afterAll, beforeAll, describe, test, afterTest } from '@dxos/test';
|
|
|
14
14
|
import { ComplexSet, range } from '@dxos/util';
|
|
15
15
|
|
|
16
16
|
import { SignalClient } from './signal-client';
|
|
17
|
+
import { type Message, type PeerInfo } from '../signal-methods';
|
|
17
18
|
|
|
18
19
|
const PAYLOAD: TaggedType<TYPES, 'google.protobuf.Any'> = {
|
|
19
20
|
'@type': 'google.protobuf.Any',
|
|
20
|
-
type_url: '
|
|
21
|
+
type_url: 'google.protobuf.Any',
|
|
21
22
|
value: Buffer.from('1'),
|
|
22
23
|
};
|
|
23
24
|
|
|
@@ -35,70 +36,76 @@ describe('SignalClient', () => {
|
|
|
35
36
|
test('message between 2 clients', async () => {
|
|
36
37
|
const [peer1, peer2] = setupPeers({ peerCount: 2 });
|
|
37
38
|
|
|
38
|
-
await peer1.client.subscribeMessages(peer1.
|
|
39
|
-
await waitForSubscription(peer1.client, peer1.
|
|
39
|
+
await peer1.client.subscribeMessages(peer1.peerInfo);
|
|
40
|
+
await waitForSubscription(peer1.client, peer1.peerKey);
|
|
40
41
|
|
|
41
42
|
const message = createMessage(peer2, peer1);
|
|
43
|
+
const receivedMessage = peer1.waitForNextMessage();
|
|
42
44
|
await peer2.client.sendMessage(message);
|
|
43
|
-
expect(await
|
|
44
|
-
})
|
|
45
|
+
expect(await receivedMessage).toEqual(message);
|
|
46
|
+
});
|
|
45
47
|
|
|
46
48
|
test('join', async () => {
|
|
47
49
|
const topic = PublicKey.random();
|
|
48
50
|
const [peer1, peer2] = setupPeers({ peerCount: 2 });
|
|
49
51
|
|
|
50
|
-
await peer1.client.join({ topic,
|
|
51
|
-
await peer2.client.join({ topic,
|
|
52
|
+
await peer1.client.join({ topic, peer: peer1.peerInfo });
|
|
53
|
+
await peer2.client.join({ topic, peer: peer2.peerInfo });
|
|
52
54
|
|
|
53
|
-
await peer1.waitForPeer(peer2.
|
|
54
|
-
await peer2.waitForPeer(peer1.
|
|
55
|
-
})
|
|
55
|
+
await peer1.waitForPeer(peer2.peerKey);
|
|
56
|
+
await peer2.waitForPeer(peer1.peerKey);
|
|
57
|
+
});
|
|
56
58
|
|
|
57
59
|
test('signal to self', async () => {
|
|
58
60
|
const [peer1, peer2] = setupPeers({ peerCount: 2 });
|
|
59
61
|
|
|
60
|
-
await peer1.client.subscribeMessages(peer1.
|
|
61
|
-
await waitForSubscription(peer1.client, peer1.
|
|
62
|
+
await peer1.client.subscribeMessages(peer1.peerInfo);
|
|
63
|
+
await waitForSubscription(peer1.client, peer1.peerKey);
|
|
62
64
|
|
|
63
65
|
const message = createMessage(peer2, peer1);
|
|
66
|
+
const receivedMessage = peer1.waitForNextMessage();
|
|
67
|
+
|
|
64
68
|
await peer1.client.sendMessage(message);
|
|
65
|
-
expect(await
|
|
66
|
-
})
|
|
69
|
+
expect(await receivedMessage).toEqual(message);
|
|
70
|
+
});
|
|
67
71
|
|
|
68
72
|
test('unsubscribe from messages', async () => {
|
|
69
73
|
const [peer1, peer2] = setupPeers({ peerCount: 2 });
|
|
70
74
|
|
|
71
|
-
await peer1.client.subscribeMessages(peer1.
|
|
72
|
-
await peer2.client.subscribeMessages(peer2.
|
|
73
|
-
await waitForSubscription(peer1.client, peer1.
|
|
75
|
+
await peer1.client.subscribeMessages(peer1.peerInfo);
|
|
76
|
+
await peer2.client.subscribeMessages(peer2.peerInfo);
|
|
77
|
+
await waitForSubscription(peer1.client, peer1.peerKey);
|
|
74
78
|
|
|
75
79
|
const message = createMessage(peer2, peer1);
|
|
76
80
|
|
|
77
81
|
{
|
|
82
|
+
const receivedMessage = peer1.waitForNextMessage();
|
|
78
83
|
await peer2.client.sendMessage(message);
|
|
79
|
-
expect(await
|
|
84
|
+
expect(await receivedMessage).toEqual(message);
|
|
80
85
|
}
|
|
81
86
|
|
|
82
87
|
// unsubscribing.
|
|
83
|
-
await peer1.client.unsubscribeMessages(peer1.
|
|
88
|
+
await peer1.client.unsubscribeMessages(peer1.peerInfo);
|
|
84
89
|
|
|
85
90
|
{
|
|
91
|
+
const receivedMessage = peer1.waitForNextMessage({ timeout: 200 });
|
|
86
92
|
await peer2.client.sendMessage(message);
|
|
87
|
-
await expect(
|
|
93
|
+
await expect(receivedMessage).toBeRejected();
|
|
88
94
|
}
|
|
89
|
-
})
|
|
95
|
+
});
|
|
90
96
|
|
|
91
97
|
test('signal after re-entrance', async () => {
|
|
92
98
|
const [peer1, peer2] = setupPeers({ peerCount: 2 });
|
|
93
99
|
|
|
94
100
|
const message = createMessage(peer2, peer1);
|
|
95
101
|
|
|
96
|
-
await peer1.client.subscribeMessages(peer1.
|
|
97
|
-
await waitForSubscription(peer1.client, peer1.
|
|
102
|
+
await peer1.client.subscribeMessages(peer1.peerInfo);
|
|
103
|
+
await waitForSubscription(peer1.client, peer1.peerKey);
|
|
98
104
|
|
|
99
105
|
{
|
|
106
|
+
const waitMessage = peer1.waitForNextMessage();
|
|
100
107
|
await peer2.client.sendMessage(message);
|
|
101
|
-
expect(await
|
|
108
|
+
expect(await waitMessage).toEqual(message);
|
|
102
109
|
}
|
|
103
110
|
|
|
104
111
|
//
|
|
@@ -107,30 +114,26 @@ describe('SignalClient', () => {
|
|
|
107
114
|
|
|
108
115
|
await peer1.client.close();
|
|
109
116
|
await peer1.client.open();
|
|
110
|
-
await waitForSubscription(peer1.client, peer1.
|
|
117
|
+
await waitForSubscription(peer1.client, peer1.peerKey);
|
|
111
118
|
|
|
112
119
|
{
|
|
120
|
+
const waitMessage = peer1.waitForNextMessage();
|
|
113
121
|
await peer2.client.sendMessage(message);
|
|
114
|
-
expect(await
|
|
122
|
+
expect(await waitMessage).toEqual(message);
|
|
115
123
|
}
|
|
116
|
-
})
|
|
124
|
+
});
|
|
117
125
|
|
|
118
126
|
const setupPeers = (options?: { broker?: SignalServerRunner; peerCount?: number }): TestPeer[] => {
|
|
119
127
|
return range(options?.peerCount ?? 1, () => {
|
|
120
128
|
const peers = new ComplexSet(PublicKey.hash);
|
|
121
|
-
|
|
122
|
-
const
|
|
123
|
-
const id = PublicKey.random();
|
|
129
|
+
const peerKey = PublicKey.random();
|
|
130
|
+
const identityKey = PublicKey.random();
|
|
124
131
|
const client = new SignalClient((options?.broker ?? broker1).url());
|
|
125
|
-
client.
|
|
126
|
-
nextMessage = msg;
|
|
127
|
-
nextMessageTrigger.wake();
|
|
128
|
-
});
|
|
129
|
-
client.swarmEvent.on(async ({ swarmEvent }) => {
|
|
132
|
+
client.swarmEvent.on(async (swarmEvent) => {
|
|
130
133
|
if (swarmEvent.peerAvailable) {
|
|
131
|
-
peers.add(PublicKey.from(swarmEvent.peerAvailable.peer));
|
|
134
|
+
peers.add(PublicKey.from(swarmEvent.peerAvailable.peer.peerKey));
|
|
132
135
|
} else if (swarmEvent.peerLeft) {
|
|
133
|
-
peers.delete(PublicKey.from(swarmEvent.peerLeft.peer));
|
|
136
|
+
peers.delete(PublicKey.from(swarmEvent.peerLeft.peer.peerKey));
|
|
134
137
|
}
|
|
135
138
|
});
|
|
136
139
|
|
|
@@ -139,26 +142,25 @@ describe('SignalClient', () => {
|
|
|
139
142
|
await client.close();
|
|
140
143
|
});
|
|
141
144
|
return {
|
|
142
|
-
|
|
145
|
+
peerKey,
|
|
146
|
+
identityKey,
|
|
143
147
|
client,
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
nextMessage = null;
|
|
151
|
-
return result;
|
|
148
|
+
peerInfo: { peerKey: peerKey.toHex(), identityKey: identityKey.toHex() },
|
|
149
|
+
waitForNextMessage: async () => {
|
|
150
|
+
return asyncTimeout(
|
|
151
|
+
client.onMessage.waitFor(() => true),
|
|
152
|
+
5000,
|
|
153
|
+
);
|
|
152
154
|
},
|
|
153
155
|
waitForPeer: (peerId: PublicKey) => waitForCondition({ condition: () => peers.has(peerId) }),
|
|
154
156
|
};
|
|
155
157
|
});
|
|
156
158
|
};
|
|
157
159
|
|
|
158
|
-
const createMessage = (from: TestPeer, to: TestPeer, payload:
|
|
160
|
+
const createMessage = (from: TestPeer, to: TestPeer, payload: Any = PAYLOAD): Message => {
|
|
159
161
|
return {
|
|
160
|
-
author: from.
|
|
161
|
-
recipient: to.
|
|
162
|
+
author: { peerKey: from.peerKey.toHex() },
|
|
163
|
+
recipient: { peerKey: to.peerKey.toHex() },
|
|
162
164
|
payload: PAYLOAD,
|
|
163
165
|
};
|
|
164
166
|
};
|
|
@@ -172,8 +174,10 @@ describe('SignalClient', () => {
|
|
|
172
174
|
});
|
|
173
175
|
|
|
174
176
|
interface TestPeer {
|
|
175
|
-
|
|
177
|
+
peerKey: PublicKey;
|
|
178
|
+
identityKey: PublicKey;
|
|
176
179
|
client: SignalClient;
|
|
180
|
+
peerInfo: PeerInfo;
|
|
177
181
|
waitForNextMessage: (options?: { timeout?: number }) => Promise<any>;
|
|
178
182
|
waitForPeer: (peerId: PublicKey) => Promise<boolean>;
|
|
179
183
|
}
|
|
@@ -8,12 +8,18 @@ import { invariant } from '@dxos/invariant';
|
|
|
8
8
|
import { PublicKey } from '@dxos/keys';
|
|
9
9
|
import { log } from '@dxos/log';
|
|
10
10
|
import { trace } from '@dxos/protocols';
|
|
11
|
-
import { SignalState
|
|
11
|
+
import { SignalState } from '@dxos/protocols/proto/dxos/mesh/signal';
|
|
12
12
|
|
|
13
13
|
import { SignalClientMonitor } from './signal-client-monitor';
|
|
14
14
|
import { SignalLocalState } from './signal-local-state';
|
|
15
15
|
import { SignalRPCClient } from './signal-rpc-client';
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
type PeerInfo,
|
|
18
|
+
type Message,
|
|
19
|
+
type SignalClientMethods,
|
|
20
|
+
type SignalStatus,
|
|
21
|
+
type SwarmEvent,
|
|
22
|
+
} from '../signal-methods';
|
|
17
23
|
|
|
18
24
|
const DEFAULT_RECONNECT_TIMEOUT = 100;
|
|
19
25
|
const MAX_RECONNECT_TIMEOUT = 5_000;
|
|
@@ -56,7 +62,7 @@ export class SignalClient extends Resource implements SignalClientMethods {
|
|
|
56
62
|
readonly statusChanged = new Event<SignalStatus>();
|
|
57
63
|
|
|
58
64
|
public readonly onMessage = new Event<Message>();
|
|
59
|
-
public readonly swarmEvent = new Event<
|
|
65
|
+
public readonly swarmEvent = new Event<SwarmEvent>();
|
|
60
66
|
|
|
61
67
|
/**
|
|
62
68
|
* @param _host Signal server websocket URL.
|
|
@@ -162,36 +168,44 @@ export class SignalClient extends Resource implements SignalClientMethods {
|
|
|
162
168
|
};
|
|
163
169
|
}
|
|
164
170
|
|
|
165
|
-
async join(args: { topic: PublicKey;
|
|
166
|
-
log('joining', { topic: args.topic, peerId: args.
|
|
171
|
+
async join(args: { topic: PublicKey; peer: PeerInfo }): Promise<void> {
|
|
172
|
+
log('joining', { topic: args.topic, peerId: args.peer.peerKey });
|
|
167
173
|
this._monitor.recordJoin();
|
|
168
|
-
this.localState.join(args);
|
|
174
|
+
this.localState.join({ topic: args.topic, peerId: PublicKey.from(args.peer.peerKey) });
|
|
169
175
|
this._reconcileTask?.schedule();
|
|
170
176
|
}
|
|
171
177
|
|
|
172
|
-
async leave(args: { topic: PublicKey;
|
|
173
|
-
log('leaving', { topic: args.topic, peerId: args.
|
|
178
|
+
async leave(args: { topic: PublicKey; peer: PeerInfo }): Promise<void> {
|
|
179
|
+
log('leaving', { topic: args.topic, peerId: args.peer.peerKey });
|
|
174
180
|
this._monitor.recordLeave();
|
|
175
|
-
this.localState.leave(args);
|
|
181
|
+
this.localState.leave({ topic: args.topic, peerId: PublicKey.from(args.peer.peerKey) });
|
|
176
182
|
}
|
|
177
183
|
|
|
178
184
|
async sendMessage(msg: Message): Promise<void> {
|
|
179
185
|
return this._monitor.recordMessageSending(msg, async () => {
|
|
180
186
|
await this._clientReady.wait();
|
|
181
187
|
invariant(this._state === SignalState.CONNECTED, 'Not connected to Signal Server');
|
|
182
|
-
|
|
188
|
+
invariant(msg.author.peerKey, 'Author key required');
|
|
189
|
+
invariant(msg.recipient.peerKey, 'Recipient key required');
|
|
190
|
+
await this._client!.sendMessage({
|
|
191
|
+
author: PublicKey.from(msg.author.peerKey),
|
|
192
|
+
recipient: PublicKey.from(msg.recipient.peerKey),
|
|
193
|
+
payload: msg.payload,
|
|
194
|
+
});
|
|
183
195
|
});
|
|
184
196
|
}
|
|
185
197
|
|
|
186
|
-
async subscribeMessages(
|
|
187
|
-
|
|
188
|
-
|
|
198
|
+
async subscribeMessages(peer: PeerInfo) {
|
|
199
|
+
invariant(peer.peerKey, 'Peer key required');
|
|
200
|
+
log('subscribing to messages', { peer });
|
|
201
|
+
this.localState.subscribeMessages(PublicKey.from(peer.peerKey));
|
|
189
202
|
this._reconcileTask?.schedule();
|
|
190
203
|
}
|
|
191
204
|
|
|
192
|
-
async unsubscribeMessages(
|
|
193
|
-
|
|
194
|
-
|
|
205
|
+
async unsubscribeMessages(peer: PeerInfo) {
|
|
206
|
+
invariant(peer.peerKey, 'Peer key required');
|
|
207
|
+
log('unsubscribing from messages', { peer });
|
|
208
|
+
this.localState.unsubscribeMessages(PublicKey.from(peer.peerKey));
|
|
195
209
|
}
|
|
196
210
|
|
|
197
211
|
private _scheduleReconcileAfterError() {
|
|
@@ -3,21 +3,24 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { asyncTimeout, Event } from '@dxos/async';
|
|
6
|
-
import type {
|
|
6
|
+
import type { Stream } from '@dxos/codec-protobuf';
|
|
7
7
|
import { cancelWithContext, type Context } from '@dxos/context';
|
|
8
8
|
import { PublicKey } from '@dxos/keys';
|
|
9
9
|
import { log } from '@dxos/log';
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
type Message as SignalMessage,
|
|
12
|
+
type SwarmEvent as SwarmEventProto,
|
|
13
|
+
} from '@dxos/protocols/proto/dxos/mesh/signal';
|
|
11
14
|
import { ComplexMap, ComplexSet, safeAwaitAll } from '@dxos/util';
|
|
12
15
|
|
|
13
16
|
import { type SignalRPCClient } from './signal-rpc-client';
|
|
14
|
-
import type { Message } from '../signal-methods';
|
|
17
|
+
import type { Message, SwarmEvent } from '../signal-methods';
|
|
15
18
|
|
|
16
19
|
export class SignalLocalState {
|
|
17
20
|
/**
|
|
18
21
|
* Swarm events streams. Keys represent actually joined topic and peerId.
|
|
19
22
|
*/
|
|
20
|
-
private readonly _swarmStreams = new ComplexMap<{ topic: PublicKey; peerId: PublicKey }, Stream<
|
|
23
|
+
private readonly _swarmStreams = new ComplexMap<{ topic: PublicKey; peerId: PublicKey }, Stream<SwarmEventProto>>(
|
|
21
24
|
({ topic, peerId }) => topic.toHex() + peerId.toHex(),
|
|
22
25
|
);
|
|
23
26
|
|
|
@@ -46,8 +49,8 @@ export class SignalLocalState {
|
|
|
46
49
|
readonly reconciled = new Event();
|
|
47
50
|
|
|
48
51
|
constructor(
|
|
49
|
-
private readonly _onMessage: (params:
|
|
50
|
-
private readonly _onSwarmEvent: (params:
|
|
52
|
+
private readonly _onMessage: (params: Message) => Promise<void>,
|
|
53
|
+
private readonly _onSwarmEvent: (params: SwarmEvent) => Promise<void>,
|
|
51
54
|
) {}
|
|
52
55
|
|
|
53
56
|
async safeCloseStreams(): Promise<{ failureCount: number }> {
|
|
@@ -107,10 +110,25 @@ export class SignalLocalState {
|
|
|
107
110
|
const swarmStream = await asyncTimeout(cancelWithContext(ctx, client.join({ topic, peerId })), 5_000);
|
|
108
111
|
// Subscribing to swarm events.
|
|
109
112
|
// TODO(mykola): What happens when the swarm stream is closed? Maybe send leave event for each peer?
|
|
110
|
-
swarmStream.subscribe(async (swarmEvent:
|
|
113
|
+
swarmStream.subscribe(async (swarmEvent: SwarmEventProto) => {
|
|
111
114
|
if (this._joinedTopics.has({ topic, peerId })) {
|
|
112
115
|
log('swarm event', { swarmEvent });
|
|
113
|
-
|
|
116
|
+
const event: SwarmEvent = swarmEvent.peerAvailable
|
|
117
|
+
? {
|
|
118
|
+
topic,
|
|
119
|
+
peerAvailable: {
|
|
120
|
+
...swarmEvent.peerAvailable,
|
|
121
|
+
peer: { peerKey: PublicKey.from(swarmEvent.peerAvailable.peer).toHex() },
|
|
122
|
+
},
|
|
123
|
+
}
|
|
124
|
+
: {
|
|
125
|
+
topic,
|
|
126
|
+
peerLeft: {
|
|
127
|
+
...swarmEvent.peerLeft,
|
|
128
|
+
peer: { peerKey: PublicKey.from(swarmEvent.peerLeft!.peer).toHex() },
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
await this._onSwarmEvent(event);
|
|
114
132
|
}
|
|
115
133
|
});
|
|
116
134
|
|
|
@@ -141,8 +159,8 @@ export class SignalLocalState {
|
|
|
141
159
|
messageStream.subscribe(async (signalMessage: SignalMessage) => {
|
|
142
160
|
if (this._subscribedMessages.has({ peerId })) {
|
|
143
161
|
const message: Message = {
|
|
144
|
-
author: PublicKey.from(signalMessage.author),
|
|
145
|
-
recipient: PublicKey.from(signalMessage.recipient),
|
|
162
|
+
author: { peerKey: PublicKey.from(signalMessage.author).toHex() },
|
|
163
|
+
recipient: { peerKey: PublicKey.from(signalMessage.recipient).toHex() },
|
|
146
164
|
payload: signalMessage.payload,
|
|
147
165
|
};
|
|
148
166
|
await this._onMessage(message);
|
|
@@ -3,68 +3,64 @@
|
|
|
3
3
|
//
|
|
4
4
|
import { EdgeClient } from '@dxos/edge-client';
|
|
5
5
|
import { PublicKey } from '@dxos/keys';
|
|
6
|
-
import { describe, openAndClose, test } from '@dxos/test';
|
|
6
|
+
import { afterTest, describe, openAndClose, test } from '@dxos/test';
|
|
7
7
|
|
|
8
|
-
import {
|
|
9
|
-
import { type
|
|
10
|
-
import { expectPeerAvailable, expectPeerLeft, expectReceivedMessage } from '../testing';
|
|
8
|
+
import { EdgeSignalManager } from './edge-signal-manager';
|
|
9
|
+
import { createMessage, expectReceivedMessage, TestBuilder, type TestBuilderOptions } from '../testing';
|
|
11
10
|
|
|
12
|
-
// TODO(mykola): Expects wrangler dev
|
|
11
|
+
// TODO(mykola): Expects wrangler dev in edge repo to run. Skip to pass CI.
|
|
13
12
|
describe.skip('EdgeSignalManager', () => {
|
|
14
|
-
const
|
|
15
|
-
const [identityKey, deviceKey] = PublicKey.randomSequence();
|
|
16
|
-
|
|
13
|
+
const edgeSignalFactory: TestBuilderOptions['signalManagerFactory'] = async (identityKey, deviceKey) => {
|
|
17
14
|
const client = new EdgeClient(identityKey, deviceKey, { socketEndpoint: 'ws://localhost:8787' });
|
|
18
15
|
await openAndClose(client);
|
|
19
|
-
const edgeSignal = new EdgeSignal({ messengerClient: client });
|
|
20
|
-
await openAndClose(edgeSignal);
|
|
21
16
|
|
|
22
|
-
return {
|
|
17
|
+
return new EdgeSignalManager({ edgeConnection: client });
|
|
23
18
|
};
|
|
24
19
|
|
|
25
20
|
test('two peers discover each other', async () => {
|
|
21
|
+
const builder = new TestBuilder({ signalManagerFactory: edgeSignalFactory });
|
|
22
|
+
afterTest(() => builder.close());
|
|
23
|
+
const [peer1, peer2] = await builder.createPeers(2);
|
|
24
|
+
|
|
26
25
|
const topic = PublicKey.random();
|
|
27
|
-
const peer1 = await setupPeer();
|
|
28
|
-
const peer2 = await setupPeer();
|
|
29
26
|
|
|
30
|
-
const discover12 =
|
|
31
|
-
const discover21 =
|
|
27
|
+
const discover12 = peer1.waitForPeerAvailable(topic, peer2.peerInfo);
|
|
28
|
+
const discover21 = peer2.waitForPeerAvailable(topic, peer1.peerInfo);
|
|
32
29
|
|
|
33
|
-
await peer1.
|
|
34
|
-
await peer2.
|
|
30
|
+
await peer1.signalManager.join({ topic, peer: peer1.peerInfo });
|
|
31
|
+
await peer2.signalManager.join({ topic, peer: peer2.peerInfo });
|
|
35
32
|
|
|
36
33
|
await discover12;
|
|
37
34
|
await discover21;
|
|
38
35
|
});
|
|
39
36
|
|
|
40
37
|
test('join and leave swarm', async () => {
|
|
38
|
+
const builder = new TestBuilder({ signalManagerFactory: edgeSignalFactory });
|
|
39
|
+
afterTest(() => builder.close());
|
|
40
|
+
const [peer1, peer2] = await builder.createPeers(2);
|
|
41
|
+
|
|
41
42
|
const topic = PublicKey.random();
|
|
42
|
-
const peer1 = await setupPeer();
|
|
43
|
-
const peer2 = await setupPeer();
|
|
44
43
|
|
|
45
|
-
const discover12 =
|
|
46
|
-
const left12 =
|
|
44
|
+
const discover12 = peer1.waitForPeerAvailable(topic, peer2.peerInfo);
|
|
45
|
+
const left12 = peer1.waitForPeerLeft(topic, peer2.peerInfo);
|
|
47
46
|
|
|
48
|
-
await
|
|
49
|
-
await
|
|
47
|
+
await peer2.signalManager.join({ topic, peer: peer2.peerInfo });
|
|
48
|
+
await peer1.signalManager.join({ topic, peer: peer1.peerInfo });
|
|
50
49
|
await discover12;
|
|
51
50
|
|
|
52
|
-
await peer2.
|
|
51
|
+
await peer2.signalManager.leave({ topic, peer: peer2.peerInfo });
|
|
53
52
|
await left12;
|
|
54
53
|
});
|
|
55
54
|
|
|
56
55
|
test('message between peers', async () => {
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const receivedMessage = expectReceivedMessage(peer2.edgeSignal, message);
|
|
66
|
-
await peer2.edgeSignal.subscribeMessages(peer2.deviceKey);
|
|
67
|
-
await peer1.edgeSignal.sendMessage(message);
|
|
56
|
+
const builder = new TestBuilder({ signalManagerFactory: edgeSignalFactory });
|
|
57
|
+
afterTest(() => builder.close());
|
|
58
|
+
const [peer1, peer2] = await builder.createPeers(2);
|
|
59
|
+
const message = createMessage(peer1.peerInfo, peer2.peerInfo);
|
|
60
|
+
|
|
61
|
+
const receivedMessage = expectReceivedMessage(peer2.signalManager.onMessage, message);
|
|
62
|
+
await peer2.signalManager.subscribeMessages(peer2.peerInfo);
|
|
63
|
+
await peer1.signalManager.sendMessage(message);
|
|
68
64
|
|
|
69
65
|
await receivedMessage;
|
|
70
66
|
});
|