@dxos/network-manager 0.1.0

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.
Files changed (184) hide show
  1. package/LICENSE +21 -0
  2. package/dist/src/connection-log.d.ts +23 -0
  3. package/dist/src/connection-log.d.ts.map +1 -0
  4. package/dist/src/connection-log.js +98 -0
  5. package/dist/src/connection-log.js.map +1 -0
  6. package/dist/src/index.d.ts +9 -0
  7. package/dist/src/index.d.ts.map +1 -0
  8. package/dist/src/index.js +28 -0
  9. package/dist/src/index.js.map +1 -0
  10. package/dist/src/network-manager.d.ts +80 -0
  11. package/dist/src/network-manager.d.ts.map +1 -0
  12. package/dist/src/network-manager.js +123 -0
  13. package/dist/src/network-manager.js.map +1 -0
  14. package/dist/src/network-manager.test.d.ts +2 -0
  15. package/dist/src/network-manager.test.d.ts.map +1 -0
  16. package/dist/src/network-manager.test.js +621 -0
  17. package/dist/src/network-manager.test.js.map +1 -0
  18. package/dist/src/presence.test.d.ts +2 -0
  19. package/dist/src/presence.test.d.ts.map +1 -0
  20. package/dist/src/presence.test.js +60 -0
  21. package/dist/src/presence.test.js.map +1 -0
  22. package/dist/src/protocol-factory.d.ts +30 -0
  23. package/dist/src/protocol-factory.d.ts.map +1 -0
  24. package/dist/src/protocol-factory.js +64 -0
  25. package/dist/src/protocol-factory.js.map +1 -0
  26. package/dist/src/signal/index.d.ts +4 -0
  27. package/dist/src/signal/index.d.ts.map +1 -0
  28. package/dist/src/signal/index.js +23 -0
  29. package/dist/src/signal/index.js.map +1 -0
  30. package/dist/src/signal/integration.test.d.ts +2 -0
  31. package/dist/src/signal/integration.test.d.ts.map +1 -0
  32. package/dist/src/signal/integration.test.js +105 -0
  33. package/dist/src/signal/integration.test.js.map +1 -0
  34. package/dist/src/signal/message-router.d.ts +39 -0
  35. package/dist/src/signal/message-router.d.ts.map +1 -0
  36. package/dist/src/signal/message-router.js +135 -0
  37. package/dist/src/signal/message-router.js.map +1 -0
  38. package/dist/src/signal/message-router.test.d.ts +2 -0
  39. package/dist/src/signal/message-router.test.d.ts.map +1 -0
  40. package/dist/src/signal/message-router.test.js +211 -0
  41. package/dist/src/signal/message-router.test.js.map +1 -0
  42. package/dist/src/signal/signal-connection.d.ts +21 -0
  43. package/dist/src/signal/signal-connection.d.ts.map +1 -0
  44. package/dist/src/signal/signal-connection.js +6 -0
  45. package/dist/src/signal/signal-connection.js.map +1 -0
  46. package/dist/src/signal/signal-messaging.d.ts +34 -0
  47. package/dist/src/signal/signal-messaging.d.ts.map +1 -0
  48. package/dist/src/signal/signal-messaging.js +6 -0
  49. package/dist/src/signal/signal-messaging.js.map +1 -0
  50. package/dist/src/swarm/connection.d.ts +69 -0
  51. package/dist/src/swarm/connection.d.ts.map +1 -0
  52. package/dist/src/swarm/connection.js +187 -0
  53. package/dist/src/swarm/connection.js.map +1 -0
  54. package/dist/src/swarm/index.d.ts +4 -0
  55. package/dist/src/swarm/index.d.ts.map +1 -0
  56. package/dist/src/swarm/index.js +23 -0
  57. package/dist/src/swarm/index.js.map +1 -0
  58. package/dist/src/swarm/swarm-mapper.d.ts +30 -0
  59. package/dist/src/swarm/swarm-mapper.d.ts.map +1 -0
  60. package/dist/src/swarm/swarm-mapper.js +90 -0
  61. package/dist/src/swarm/swarm-mapper.js.map +1 -0
  62. package/dist/src/swarm/swarm.d.ts +64 -0
  63. package/dist/src/swarm/swarm.d.ts.map +1 -0
  64. package/dist/src/swarm/swarm.js +276 -0
  65. package/dist/src/swarm/swarm.js.map +1 -0
  66. package/dist/src/swarm/swarm.test.d.ts +2 -0
  67. package/dist/src/swarm/swarm.test.d.ts.map +1 -0
  68. package/dist/src/swarm/swarm.test.js +145 -0
  69. package/dist/src/swarm/swarm.test.js.map +1 -0
  70. package/dist/src/testing/index.d.ts +2 -0
  71. package/dist/src/testing/index.d.ts.map +1 -0
  72. package/dist/src/testing/index.js +21 -0
  73. package/dist/src/testing/index.js.map +1 -0
  74. package/dist/src/testing/test-protocol.d.ts +59 -0
  75. package/dist/src/testing/test-protocol.d.ts.map +1 -0
  76. package/dist/src/testing/test-protocol.js +140 -0
  77. package/dist/src/testing/test-protocol.js.map +1 -0
  78. package/dist/src/topology/fully-connected-topology.d.ts +11 -0
  79. package/dist/src/topology/fully-connected-topology.d.ts.map +1 -0
  80. package/dist/src/topology/fully-connected-topology.js +34 -0
  81. package/dist/src/topology/fully-connected-topology.js.map +1 -0
  82. package/dist/src/topology/index.d.ts +5 -0
  83. package/dist/src/topology/index.d.ts.map +1 -0
  84. package/dist/src/topology/index.js +24 -0
  85. package/dist/src/topology/index.js.map +1 -0
  86. package/dist/src/topology/mmst-topology.d.ts +31 -0
  87. package/dist/src/topology/mmst-topology.d.ts.map +1 -0
  88. package/dist/src/topology/mmst-topology.js +73 -0
  89. package/dist/src/topology/mmst-topology.js.map +1 -0
  90. package/dist/src/topology/star-topology.d.ts +13 -0
  91. package/dist/src/topology/star-topology.d.ts.map +1 -0
  92. package/dist/src/topology/star-topology.js +60 -0
  93. package/dist/src/topology/star-topology.js.map +1 -0
  94. package/dist/src/topology/topology.d.ts +56 -0
  95. package/dist/src/topology/topology.d.ts.map +1 -0
  96. package/dist/src/topology/topology.js +6 -0
  97. package/dist/src/topology/topology.js.map +1 -0
  98. package/dist/src/transport/index.d.ts +6 -0
  99. package/dist/src/transport/index.d.ts.map +1 -0
  100. package/dist/src/transport/index.js +25 -0
  101. package/dist/src/transport/index.js.map +1 -0
  102. package/dist/src/transport/memory-transport.d.ts +32 -0
  103. package/dist/src/transport/memory-transport.d.ts.map +1 -0
  104. package/dist/src/transport/memory-transport.js +98 -0
  105. package/dist/src/transport/memory-transport.js.map +1 -0
  106. package/dist/src/transport/memory-transport.test.d.ts +2 -0
  107. package/dist/src/transport/memory-transport.test.d.ts.map +1 -0
  108. package/dist/src/transport/memory-transport.test.js +84 -0
  109. package/dist/src/transport/memory-transport.test.js.map +1 -0
  110. package/dist/src/transport/transport.d.ts +38 -0
  111. package/dist/src/transport/transport.d.ts.map +1 -0
  112. package/dist/src/transport/transport.js +6 -0
  113. package/dist/src/transport/transport.js.map +1 -0
  114. package/dist/src/transport/webrtc-transport-proxy.d.ts +48 -0
  115. package/dist/src/transport/webrtc-transport-proxy.d.ts.map +1 -0
  116. package/dist/src/transport/webrtc-transport-proxy.js +139 -0
  117. package/dist/src/transport/webrtc-transport-proxy.js.map +1 -0
  118. package/dist/src/transport/webrtc-transport-proxy.test.d.ts +2 -0
  119. package/dist/src/transport/webrtc-transport-proxy.test.d.ts.map +1 -0
  120. package/dist/src/transport/webrtc-transport-proxy.test.js +245 -0
  121. package/dist/src/transport/webrtc-transport-proxy.test.js.map +1 -0
  122. package/dist/src/transport/webrtc-transport-service.d.ts +15 -0
  123. package/dist/src/transport/webrtc-transport-service.d.ts.map +1 -0
  124. package/dist/src/transport/webrtc-transport-service.js +97 -0
  125. package/dist/src/transport/webrtc-transport-service.js.map +1 -0
  126. package/dist/src/transport/webrtc-transport.d.ts +34 -0
  127. package/dist/src/transport/webrtc-transport.d.ts.map +1 -0
  128. package/dist/src/transport/webrtc-transport.js +100 -0
  129. package/dist/src/transport/webrtc-transport.js.map +1 -0
  130. package/dist/src/transport/webrtc-transport.test.d.ts +2 -0
  131. package/dist/src/transport/webrtc-transport.test.d.ts.map +1 -0
  132. package/dist/src/transport/webrtc-transport.test.js +80 -0
  133. package/dist/src/transport/webrtc-transport.test.js.map +1 -0
  134. package/dist/src/transport/webrtc.d.ts +6 -0
  135. package/dist/src/transport/webrtc.d.ts.map +1 -0
  136. package/dist/src/transport/webrtc.js +17 -0
  137. package/dist/src/transport/webrtc.js.map +1 -0
  138. package/dist/src/transport/wrtc-simple-peer.test.d.ts +2 -0
  139. package/dist/src/transport/wrtc-simple-peer.test.d.ts.map +1 -0
  140. package/dist/src/transport/wrtc-simple-peer.test.js +24 -0
  141. package/dist/src/transport/wrtc-simple-peer.test.js.map +1 -0
  142. package/dist/src/types.d.ts +6 -0
  143. package/dist/src/types.d.ts.map +1 -0
  144. package/dist/src/types.js +6 -0
  145. package/dist/src/types.js.map +1 -0
  146. package/package.json +58 -0
  147. package/src/connection-log.ts +102 -0
  148. package/src/globals.d.ts +7 -0
  149. package/src/index.ts +12 -0
  150. package/src/network-manager.test.ts +764 -0
  151. package/src/network-manager.ts +204 -0
  152. package/src/presence.test.ts +78 -0
  153. package/src/protocol-factory.ts +83 -0
  154. package/src/signal/index.ts +7 -0
  155. package/src/signal/integration.test.ts +129 -0
  156. package/src/signal/message-router.test.ts +274 -0
  157. package/src/signal/message-router.ts +200 -0
  158. package/src/signal/signal-connection.ts +20 -0
  159. package/src/signal/signal-messaging.ts +38 -0
  160. package/src/swarm/connection.ts +206 -0
  161. package/src/swarm/index.ts +7 -0
  162. package/src/swarm/swarm-mapper.ts +120 -0
  163. package/src/swarm/swarm.test.ts +192 -0
  164. package/src/swarm/swarm.ts +328 -0
  165. package/src/testing/index.ts +5 -0
  166. package/src/testing/test-protocol.ts +160 -0
  167. package/src/topology/fully-connected-topology.ts +38 -0
  168. package/src/topology/index.ts +8 -0
  169. package/src/topology/mmst-topology.ts +105 -0
  170. package/src/topology/star-topology.ts +67 -0
  171. package/src/topology/topology.ts +69 -0
  172. package/src/transport/index.ts +9 -0
  173. package/src/transport/memory-transport.test.ts +110 -0
  174. package/src/transport/memory-transport.ts +128 -0
  175. package/src/transport/transport.ts +47 -0
  176. package/src/transport/webrtc-transport-proxy.test.ts +290 -0
  177. package/src/transport/webrtc-transport-proxy.ts +167 -0
  178. package/src/transport/webrtc-transport-service.ts +115 -0
  179. package/src/transport/webrtc-transport.test.ts +112 -0
  180. package/src/transport/webrtc-transport.ts +122 -0
  181. package/src/transport/webrtc.ts +15 -0
  182. package/src/transport/wrtc-simple-peer.test.ts +24 -0
  183. package/src/types.ts +10 -0
  184. package/src/typings.d.ts +7 -0
@@ -0,0 +1,204 @@
1
+ //
2
+ // Copyright 2020 DXOS.org
3
+ //
4
+
5
+ import assert from 'node:assert';
6
+
7
+ import { Event } from '@dxos/async';
8
+ import { PublicKey } from '@dxos/keys';
9
+ import { log } from '@dxos/log';
10
+ import { Protocol } from '@dxos/mesh-protocol';
11
+ import { Messenger, SignalManager } from '@dxos/messaging';
12
+ import { ComplexMap } from '@dxos/util';
13
+
14
+ import { ConnectionLog } from './connection-log';
15
+ import { SignalConnection } from './signal';
16
+ import { Swarm, SwarmMapper } from './swarm';
17
+ import { Topology } from './topology';
18
+ import { TransportFactory } from './transport';
19
+
20
+ export type ProtocolProvider = (opts: { channel: Buffer; initiator: boolean }) => Protocol;
21
+
22
+ export type SwarmConnection = {
23
+ close(): Promise<void>;
24
+ };
25
+
26
+ // TODO(burdon): Timeout.
27
+ export type SwarmOptions = {
28
+ /**
29
+ * Swarm topic.
30
+ */
31
+ topic: PublicKey;
32
+
33
+ /**
34
+ * This node's peer id.
35
+ */
36
+ peerId: PublicKey;
37
+
38
+ /**
39
+ * Protocol to use for every connection.
40
+ */
41
+ protocol: ProtocolProvider;
42
+
43
+ /**
44
+ * Requested topology. Must be a new instance for every swarm.
45
+ */
46
+ topology?: Topology;
47
+
48
+ /**
49
+ * Presence plugin for network mapping, if exists.
50
+ */
51
+ presence?: any;
52
+
53
+ /**
54
+ * Custom label assigned to this swarm. Used in devtools to display human-readable names for swarms.
55
+ */
56
+ label?: string;
57
+ };
58
+
59
+ export type NetworkManagerOptions = {
60
+ transportFactory: TransportFactory;
61
+ signalManager: SignalManager;
62
+ log?: boolean; // TODO(burdon): Remove.
63
+ };
64
+
65
+ /**
66
+ * Manages connection to the swarm.
67
+ */
68
+ export class NetworkManager {
69
+ private readonly _transportFactory: TransportFactory;
70
+
71
+ private readonly _swarms = new ComplexMap<PublicKey, Swarm>(PublicKey.hash);
72
+ private readonly _mappers = new ComplexMap<PublicKey, SwarmMapper>(PublicKey.hash);
73
+
74
+ private readonly _signalManager: SignalManager;
75
+ private readonly _messenger: Messenger;
76
+ private readonly _signalConnection: SignalConnection;
77
+ private readonly _connectionLog?: ConnectionLog;
78
+
79
+ public readonly topicsUpdated = new Event<void>();
80
+
81
+ constructor({ transportFactory, signalManager, log }: NetworkManagerOptions) {
82
+ this._transportFactory = transportFactory;
83
+
84
+ // Listen for signal manager events.
85
+ this._signalManager = signalManager;
86
+ this._signalManager.swarmEvent.on(({ topic, swarmEvent: event }) => this._swarms.get(topic)?.onSwarmEvent(event));
87
+ this._messenger = new Messenger({ signalManager: this._signalManager });
88
+
89
+ this._signalConnection = {
90
+ join: (opts) => this._signalManager.join(opts),
91
+ leave: (opts) => this._signalManager.leave(opts)
92
+ };
93
+
94
+ if (log) {
95
+ this._connectionLog = new ConnectionLog();
96
+ }
97
+ }
98
+
99
+ get signal() {
100
+ return this._signalManager;
101
+ }
102
+
103
+ // TODO(burdon): Reconcile with "discovery_key".
104
+ get topics() {
105
+ return Array.from(this._swarms.keys());
106
+ }
107
+
108
+ // TODO(burdon): Factor out devtools.
109
+ get connectionLog() {
110
+ return this._connectionLog;
111
+ }
112
+
113
+ getSwarmMap(topic: PublicKey): SwarmMapper | undefined {
114
+ return this._mappers.get(topic);
115
+ }
116
+
117
+ getSwarm(topic: PublicKey): Swarm | undefined {
118
+ return this._swarms.get(topic);
119
+ }
120
+
121
+ /**
122
+ * Join the swarm.
123
+ */
124
+ // TODO(burdon): Join/Open?
125
+ async openSwarmConnection({
126
+ topic,
127
+ peerId,
128
+ topology,
129
+ protocol,
130
+ presence,
131
+ label
132
+ }: SwarmOptions): Promise<SwarmConnection> {
133
+ assert(PublicKey.isPublicKey(topic));
134
+ assert(PublicKey.isPublicKey(peerId));
135
+ assert(topology);
136
+ assert(typeof protocol === 'function');
137
+ if (this._swarms.has(topic)) {
138
+ throw new Error(`Already connected to swarm: ${topic}`);
139
+ }
140
+
141
+ log('joining', { topic, peerId, topology: topology.toString() });
142
+ const swarm = new Swarm(topic, peerId, topology, protocol, this._messenger, this._transportFactory, label);
143
+ swarm.errors.handle((error) => {
144
+ log(`Swarm error: ${error}`);
145
+ });
146
+
147
+ this._swarms.set(topic, swarm);
148
+ this._signalConnection.join({ topic, peerId }).catch((error) => log.catch(error));
149
+ this._mappers.set(topic, new SwarmMapper(swarm, presence));
150
+
151
+ this.topicsUpdated.emit();
152
+ this._connectionLog?.swarmJoined(swarm);
153
+ log('open', { topic });
154
+
155
+ return {
156
+ close: () => this.closeSwarmConnection(topic)
157
+ };
158
+ }
159
+
160
+ /**
161
+ * Close the connection.
162
+ */
163
+ async closeSwarmConnection(topic: PublicKey) {
164
+ if (!this._swarms.has(topic)) {
165
+ return;
166
+ }
167
+
168
+ log('closing', { topic });
169
+ const swarm = this._swarms.get(topic)!;
170
+ await this._signalConnection.leave({ topic, peerId: swarm.ownPeerId });
171
+
172
+ const map = this._mappers.get(topic)!;
173
+ map.destroy();
174
+ this._mappers.delete(topic);
175
+
176
+ this._connectionLog?.swarmLeft(swarm);
177
+
178
+ await swarm.destroy();
179
+ this._swarms.delete(topic);
180
+
181
+ await this.topicsUpdated.emit();
182
+ log('closed', { topic });
183
+ }
184
+
185
+ /**
186
+ * @deprecated
187
+ */
188
+ // TODO(dmaretskyi): Remove.
189
+ async start() {
190
+ console.warn('NetworkManger.start is deprecated.');
191
+ }
192
+
193
+ // TODO(burdon): Open/close?
194
+ async destroy() {
195
+ for (const topic of this._swarms.keys()) {
196
+ await this.closeSwarmConnection(topic).catch((err) => {
197
+ log(`Failed to leave swarm ${topic} on NetworkManager.destroy}`);
198
+ log(err);
199
+ });
200
+ }
201
+
202
+ await this._signalManager.destroy();
203
+ }
204
+ }
@@ -0,0 +1,78 @@
1
+ //
2
+ // Copyright 2021 DXOS.org
3
+ //
4
+
5
+ import expect from 'expect';
6
+ import waitForExpect from 'wait-for-expect';
7
+
8
+ import { PublicKey } from '@dxos/keys';
9
+ import { MemorySignalManagerContext, MemorySignalManager } from '@dxos/messaging';
10
+ import { PresencePlugin } from '@dxos/protocol-plugin-presence';
11
+ import { afterTest } from '@dxos/testutils';
12
+
13
+ import { NetworkManager } from './network-manager';
14
+ import { createProtocolFactory } from './protocol-factory';
15
+ import { FullyConnectedTopology } from './topology';
16
+ import { MemoryTransportFactory } from './transport';
17
+
18
+ const signalContext = new MemorySignalManagerContext();
19
+
20
+ const createPeer = async (topic: PublicKey) => {
21
+ const peerId = PublicKey.random();
22
+
23
+ const networkManager = new NetworkManager({
24
+ signalManager: new MemorySignalManager(signalContext),
25
+ transportFactory: MemoryTransportFactory
26
+ });
27
+ afterTest(() => networkManager.destroy());
28
+
29
+ const presencePlugin = new PresencePlugin(peerId.asBuffer());
30
+ afterTest(() => presencePlugin.stop());
31
+
32
+ await networkManager.openSwarmConnection({
33
+ peerId,
34
+ protocol: createProtocolFactory(topic, peerId, [presencePlugin]),
35
+ topic,
36
+ topology: new FullyConnectedTopology()
37
+ });
38
+
39
+ return { peerId, presence: presencePlugin, networkManager };
40
+ };
41
+
42
+ describe('Presence', function () {
43
+ it('sees connected peers', async function () {
44
+ const topic = PublicKey.random();
45
+ const peer1 = await createPeer(topic);
46
+ const peer2 = await createPeer(topic);
47
+
48
+ await waitForExpect(() => {
49
+ expect(peer1.presence.peers.map((key) => key.toString('hex')).sort()).toEqual(
50
+ [peer1, peer2].map((key) => key.peerId.toHex()).sort()
51
+ );
52
+
53
+ expect(peer2.presence.peers.map((key) => key.toString('hex')).sort()).toEqual(
54
+ [peer1, peer2].map((key) => key.peerId.toHex()).sort()
55
+ );
56
+ });
57
+ });
58
+
59
+ it('removes disconnected peers', async function () {
60
+ const topic = PublicKey.random();
61
+ const peer1 = await createPeer(topic);
62
+ const peer2 = await createPeer(topic);
63
+
64
+ await waitForExpect(() => {
65
+ expect(peer1.presence.peers.map((key) => key.toString('hex')).sort()).toEqual(
66
+ [peer1, peer2].map((key) => key.peerId.toHex()).sort()
67
+ );
68
+ });
69
+
70
+ await peer2.networkManager.closeSwarmConnection(topic);
71
+
72
+ await waitForExpect(() => {
73
+ expect(peer1.presence.peers.map((key) => key.toString('hex')).sort()).toEqual(
74
+ [peer1].map((x) => x.peerId.toHex()).sort()
75
+ );
76
+ });
77
+ });
78
+ });
@@ -0,0 +1,83 @@
1
+ //
2
+ // Copyright 2020 DXOS.org
3
+ //
4
+
5
+ import assert from 'node:assert';
6
+
7
+ import { discoveryKey } from '@dxos/crypto';
8
+ import { PublicKey } from '@dxos/keys';
9
+ import { log } from '@dxos/log';
10
+ import { Extension, Protocol } from '@dxos/mesh-protocol';
11
+
12
+ import { ProtocolProvider } from './network-manager';
13
+
14
+ interface ProtocolFactoryOptions {
15
+ plugins: any[];
16
+ getTopics: () => Buffer[];
17
+ session: Record<string, any>;
18
+ }
19
+
20
+ /**
21
+ * Returns a function that takes a channel parameter, returns a Protocol object
22
+ * with its context set to channel, plugins from plugins parameter and session
23
+ * set to session parameter.
24
+ *
25
+ * @param plugins array of Protocol plugin objects to add to created Protocol objects
26
+ * @param getTopics retrieve a list of known topic keys to encrypt by public key.
27
+ * @deprecated Use `createProtocolFactory`.
28
+ */
29
+ export const protocolFactory = ({
30
+ session = {},
31
+ plugins = [],
32
+ getTopics
33
+ }: ProtocolFactoryOptions): ProtocolProvider => {
34
+ assert(getTopics);
35
+ // eslint-disable-next-line no-unused-vars
36
+ return ({ channel, initiator }) => {
37
+ const protocol = new Protocol({
38
+ streamOptions: { live: true },
39
+ discoveryToPublicKey: (dk) => {
40
+ const publicKey = getTopics().find((topic) => discoveryKey(topic).equals(dk));
41
+ if (publicKey) {
42
+ protocol.setContext({ topic: PublicKey.stringify(publicKey) });
43
+ }
44
+ assert(publicKey, 'PublicKey not found in discovery.');
45
+ return publicKey;
46
+ },
47
+ initiator,
48
+ userSession: session,
49
+ discoveryKey: channel
50
+ });
51
+
52
+ protocol.setExtensions(plugins.map((plugin) => plugin.createExtension())).init();
53
+
54
+ log('Created protocol');
55
+ return protocol;
56
+ };
57
+ };
58
+
59
+ export interface Plugin {
60
+ createExtension: () => Extension;
61
+ }
62
+
63
+ export const createProtocolFactory = (topic: PublicKey, peerId: PublicKey, plugins: Plugin[]) =>
64
+ protocolFactory({
65
+ getTopics: () => [topic.asBuffer()],
66
+ session: { peerId: PublicKey.stringify(peerId.asBuffer()) },
67
+ plugins
68
+ });
69
+
70
+ /**
71
+ * Creates a ProtocolProvider for simple transport connections with only one protocol plugin.
72
+ * @deprecated Use `createProtocolFactory`.
73
+ */
74
+ export const transportProtocolProvider = (
75
+ rendezvousKey: Buffer,
76
+ peerId: Buffer,
77
+ protocolPlugin: any
78
+ ): ProtocolProvider =>
79
+ protocolFactory({
80
+ getTopics: () => [rendezvousKey],
81
+ session: { peerId: PublicKey.stringify(peerId) },
82
+ plugins: [protocolPlugin]
83
+ });
@@ -0,0 +1,7 @@
1
+ //
2
+ // Copyright 2020 DXOS.org
3
+ //
4
+
5
+ export * from './signal-connection';
6
+ export * from './signal-messaging';
7
+ export * from './message-router';
@@ -0,0 +1,129 @@
1
+ //
2
+ // Copyright 2022 DXOS.org
3
+ //
4
+
5
+ // @dxos/mocha platform=nodejs
6
+
7
+ import { expect } from 'earljs';
8
+ import waitForExpect from 'wait-for-expect';
9
+
10
+ import { PublicKey } from '@dxos/keys';
11
+ import { WebsocketSignalManager } from '@dxos/messaging';
12
+ import { createTestBroker, TestBroker } from '@dxos/signal';
13
+
14
+ import { MessageRouter } from './message-router';
15
+ import { SignalMessage } from './signal-messaging';
16
+
17
+ describe('Signal Integration Test', function () {
18
+ let broker: TestBroker;
19
+
20
+ before(async function () {
21
+ broker = await createTestBroker();
22
+ });
23
+
24
+ after(function () {
25
+ broker.stop();
26
+ });
27
+
28
+ const setupPeer = ({ topic = PublicKey.random() }: { topic?: PublicKey } = {}) => {
29
+ const signalManager = new WebsocketSignalManager([broker.url()]);
30
+ signalManager.onMessage.on((message) => messageRouter.receiveMessage(message));
31
+
32
+ const receivedSignals: SignalMessage[] = [];
33
+ const signalMock = async (msg: SignalMessage) => {
34
+ receivedSignals.push(msg);
35
+ };
36
+ const messageRouter = new MessageRouter({
37
+ sendMessage: signalManager.sendMessage.bind(signalManager),
38
+ onSignal: signalMock,
39
+ onOffer: async () => ({ accept: true }),
40
+ topic
41
+ });
42
+
43
+ return {
44
+ signalManager,
45
+ receivedSignals,
46
+ messageRouter
47
+ };
48
+ };
49
+
50
+ it('two peers connecting', async function () {
51
+ const peer1 = PublicKey.random();
52
+ const peer2 = PublicKey.random();
53
+ const topic = PublicKey.random();
54
+
55
+ const peerNetworking1 = setupPeer({ topic });
56
+ const peerNetworking2 = setupPeer({ topic });
57
+
58
+ const promise1 = peerNetworking1.signalManager.swarmEvent.waitFor(
59
+ ({ swarmEvent }) => !!swarmEvent.peerAvailable && peer2.equals(swarmEvent.peerAvailable.peer)
60
+ );
61
+ const promise2 = peerNetworking1.signalManager.swarmEvent.waitFor(
62
+ ({ swarmEvent }) => !!swarmEvent.peerAvailable && peer1.equals(swarmEvent.peerAvailable.peer)
63
+ );
64
+
65
+ await peerNetworking1.signalManager.join({ topic, peerId: peer1 });
66
+ await peerNetworking2.signalManager.join({ topic, peerId: peer2 });
67
+
68
+ await promise1;
69
+ await promise2;
70
+
71
+ expect(
72
+ await peerNetworking1.messageRouter.offer({
73
+ topic,
74
+ author: peer1,
75
+ recipient: peer2,
76
+ sessionId: PublicKey.random(),
77
+ data: {
78
+ offer: {}
79
+ }
80
+ })
81
+ ).toBeAnObjectWith({ accept: true });
82
+
83
+ expect(
84
+ await peerNetworking2.messageRouter.offer({
85
+ topic,
86
+ author: peer2,
87
+ recipient: peer1,
88
+ sessionId: PublicKey.random(),
89
+ data: {
90
+ offer: {}
91
+ }
92
+ })
93
+ ).toBeAnObjectWith({ accept: true });
94
+
95
+ {
96
+ const message: SignalMessage = {
97
+ topic,
98
+ author: peer1,
99
+ recipient: peer2,
100
+ sessionId: PublicKey.random(),
101
+ data: {
102
+ signal: { json: JSON.stringify({ foo: 'bar' }) }
103
+ }
104
+ };
105
+ await peerNetworking1.messageRouter.signal(message);
106
+
107
+ await waitForExpect(() => {
108
+ expect(peerNetworking2.receivedSignals[0]).toBeAnObjectWith(message);
109
+ });
110
+ }
111
+
112
+ {
113
+ const message: SignalMessage = {
114
+ topic,
115
+ author: peer2,
116
+ recipient: peer1,
117
+ sessionId: PublicKey.random(),
118
+ data: {
119
+ signal: { json: JSON.stringify({ foo: 'bar' }) }
120
+ }
121
+ };
122
+ await peerNetworking2.messageRouter.signal(message);
123
+
124
+ await waitForExpect(() => {
125
+ expect(peerNetworking1.receivedSignals[0]).toBeAnObjectWith(message);
126
+ });
127
+ }
128
+ });
129
+ });