@dxos/network-manager 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.
Files changed (120) hide show
  1. package/LICENSE +102 -5
  2. package/README.md +1 -1
  3. package/dist/lib/browser/{chunk-HQNQOWFA.mjs → chunk-UFYPMUBI.mjs} +599 -1973
  4. package/dist/lib/browser/chunk-UFYPMUBI.mjs.map +7 -0
  5. package/dist/lib/browser/index.mjs +198 -4
  6. package/dist/lib/browser/index.mjs.map +4 -4
  7. package/dist/lib/browser/meta.json +1 -1
  8. package/dist/lib/browser/testing/index.mjs +65 -70
  9. package/dist/lib/browser/testing/index.mjs.map +3 -3
  10. package/dist/lib/browser/transport/tcp/index.mjs +2 -35
  11. package/dist/lib/browser/transport/tcp/index.mjs.map +4 -4
  12. package/dist/lib/browser/transport/tcp/tcp-transport.browser.mjs +36 -0
  13. package/dist/lib/browser/transport/tcp/tcp-transport.browser.mjs.map +7 -0
  14. package/dist/lib/browser/transport/tcp/tcp-transport.mjs +125 -0
  15. package/dist/lib/browser/transport/tcp/tcp-transport.mjs.map +7 -0
  16. package/dist/lib/node-esm/{chunk-JPPMRZTH.mjs → chunk-3KIKKHMP.mjs} +599 -1973
  17. package/dist/lib/node-esm/chunk-3KIKKHMP.mjs.map +7 -0
  18. package/dist/lib/node-esm/index.mjs +198 -4
  19. package/dist/lib/node-esm/index.mjs.map +4 -4
  20. package/dist/lib/node-esm/meta.json +1 -1
  21. package/dist/lib/node-esm/testing/index.mjs +65 -70
  22. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  23. package/dist/lib/node-esm/transport/tcp/index.mjs +2 -156
  24. package/dist/lib/node-esm/transport/tcp/index.mjs.map +4 -4
  25. package/dist/lib/node-esm/transport/tcp/tcp-transport.browser.mjs +36 -0
  26. package/dist/lib/node-esm/transport/tcp/tcp-transport.browser.mjs.map +7 -0
  27. package/dist/lib/node-esm/transport/tcp/tcp-transport.mjs +125 -0
  28. package/dist/lib/node-esm/transport/tcp/tcp-transport.mjs.map +7 -0
  29. package/dist/types/src/connection-log.d.ts.map +1 -1
  30. package/dist/types/src/index.d.ts +1 -1
  31. package/dist/types/src/index.d.ts.map +1 -1
  32. package/dist/types/src/network-manager.d.ts +6 -6
  33. package/dist/types/src/network-manager.d.ts.map +1 -1
  34. package/dist/types/src/signal/ice.d.ts.map +1 -1
  35. package/dist/types/src/signal/index.d.ts +2 -2
  36. package/dist/types/src/signal/index.d.ts.map +1 -1
  37. package/dist/types/src/signal/signal-connection.d.ts +3 -2
  38. package/dist/types/src/signal/signal-connection.d.ts.map +1 -1
  39. package/dist/types/src/signal/signal-messenger.d.ts +3 -2
  40. package/dist/types/src/signal/signal-messenger.d.ts.map +1 -1
  41. package/dist/types/src/signal/swarm-messenger.d.ts +8 -8
  42. package/dist/types/src/signal/swarm-messenger.d.ts.map +1 -1
  43. package/dist/types/src/swarm/connection-limiter.d.ts.map +1 -1
  44. package/dist/types/src/swarm/connection.d.ts +2 -2
  45. package/dist/types/src/swarm/connection.d.ts.map +1 -1
  46. package/dist/types/src/swarm/peer.d.ts +6 -5
  47. package/dist/types/src/swarm/peer.d.ts.map +1 -1
  48. package/dist/types/src/swarm/swarm-mapper.d.ts.map +1 -1
  49. package/dist/types/src/swarm/swarm.d.ts +6 -8
  50. package/dist/types/src/swarm/swarm.d.ts.map +1 -1
  51. package/dist/types/src/testing/test-builder.d.ts +1 -1
  52. package/dist/types/src/testing/test-builder.d.ts.map +1 -1
  53. package/dist/types/src/testing/test-wire-protocol.d.ts +1 -1
  54. package/dist/types/src/testing/test-wire-protocol.d.ts.map +1 -1
  55. package/dist/types/src/tests/basic-test-suite.d.ts.map +1 -1
  56. package/dist/types/src/tests/property-test-suite.d.ts.map +1 -1
  57. package/dist/types/src/tests/utils.d.ts.map +1 -1
  58. package/dist/types/src/topology/fully-connected-topology.d.ts.map +1 -1
  59. package/dist/types/src/topology/index.d.ts +1 -1
  60. package/dist/types/src/topology/index.d.ts.map +1 -1
  61. package/dist/types/src/topology/mmst-topology.d.ts.map +1 -1
  62. package/dist/types/src/topology/star-topology.d.ts.map +1 -1
  63. package/dist/types/src/transport/memory-transport.d.ts.map +1 -1
  64. package/dist/types/src/transport/tcp/index.d.ts +1 -1
  65. package/dist/types/src/transport/tcp/index.d.ts.map +1 -1
  66. package/dist/types/src/transport/tcp/tcp-transport.browser.d.ts.map +1 -1
  67. package/dist/types/src/transport/tcp/tcp-transport.d.ts.map +1 -1
  68. package/dist/types/src/transport/webrtc/rtc-peer-connection.d.ts +6 -6
  69. package/dist/types/src/transport/webrtc/rtc-peer-connection.d.ts.map +1 -1
  70. package/dist/types/src/transport/webrtc/rtc-transport-channel.d.ts +1 -1
  71. package/dist/types/src/transport/webrtc/rtc-transport-channel.d.ts.map +1 -1
  72. package/dist/types/src/transport/webrtc/rtc-transport-factory.d.ts.map +1 -1
  73. package/dist/types/src/transport/webrtc/rtc-transport-proxy.d.ts.map +1 -1
  74. package/dist/types/src/transport/webrtc/rtc-transport-service.d.ts +1 -1
  75. package/dist/types/src/transport/webrtc/rtc-transport-service.d.ts.map +1 -1
  76. package/dist/types/src/transport/webrtc/rtc-transport-stats.d.ts.map +1 -1
  77. package/dist/types/src/transport/webrtc/test-utils.d.ts.map +1 -1
  78. package/dist/types/src/transport/webrtc/utils.d.ts.map +1 -1
  79. package/dist/types/src/wire-protocol.d.ts +5 -5
  80. package/dist/types/src/wire-protocol.d.ts.map +1 -1
  81. package/dist/types/tsconfig.tsbuildinfo +1 -1
  82. package/package.json +38 -44
  83. package/src/connection-log.ts +1 -1
  84. package/src/index.ts +1 -1
  85. package/src/network-manager.ts +22 -20
  86. package/src/signal/ice.test.ts +1 -1
  87. package/src/signal/index.ts +2 -2
  88. package/src/signal/integration.node.test.ts +13 -12
  89. package/src/signal/signal-connection.ts +3 -2
  90. package/src/signal/signal-messenger.ts +3 -2
  91. package/src/signal/swarm-messenger.node.test.ts +26 -25
  92. package/src/signal/swarm-messenger.ts +66 -56
  93. package/src/swarm/connection.test.ts +9 -8
  94. package/src/swarm/connection.ts +18 -25
  95. package/src/swarm/peer.ts +9 -8
  96. package/src/swarm/swarm-mapper.ts +1 -1
  97. package/src/swarm/swarm.test.ts +8 -7
  98. package/src/swarm/swarm.ts +14 -20
  99. package/src/testing/test-builder.ts +15 -7
  100. package/src/testing/test-wire-protocol.ts +2 -2
  101. package/src/tests/basic-test-suite.ts +2 -2
  102. package/src/tests/memory-transport.test.ts +2 -2
  103. package/src/tests/property-test-suite.ts +4 -3
  104. package/src/tests/tcp-transport.node.test.ts +2 -2
  105. package/src/tests/webrtc-transport.test.ts +5 -3
  106. package/src/topology/index.ts +1 -1
  107. package/src/transport/tcp/index.ts +1 -1
  108. package/src/transport/tcp/tcp-transport.ts +1 -1
  109. package/src/transport/webrtc/rtc-connection-factory.ts +1 -1
  110. package/src/transport/webrtc/rtc-peer-connection.ts +4 -4
  111. package/src/transport/webrtc/rtc-transport-channel.test.ts +1 -1
  112. package/src/transport/webrtc/rtc-transport-channel.ts +2 -2
  113. package/src/transport/webrtc/rtc-transport-factory.ts +2 -2
  114. package/src/transport/webrtc/rtc-transport-proxy.test.ts +5 -4
  115. package/src/transport/webrtc/rtc-transport-proxy.ts +6 -4
  116. package/src/transport/webrtc/rtc-transport-service.ts +5 -5
  117. package/src/transport/webrtc/rtc-transport.test.ts +5 -4
  118. package/src/wire-protocol.ts +6 -6
  119. package/dist/lib/browser/chunk-HQNQOWFA.mjs.map +0 -7
  120. package/dist/lib/node-esm/chunk-JPPMRZTH.mjs.map +0 -7
@@ -7,7 +7,7 @@ import { Context } from '@dxos/context';
7
7
  import { invariant } from '@dxos/invariant';
8
8
  import { PublicKey } from '@dxos/keys';
9
9
  import { log } from '@dxos/log';
10
- import { type PeerInfo, type Message } from '@dxos/messaging';
10
+ import { type Message, type PeerInfo } from '@dxos/messaging';
11
11
  import { TimeoutError } from '@dxos/protocols';
12
12
  import { schema } from '@dxos/protocols/proto';
13
13
  import { type Answer, type SwarmMessage } from '@dxos/protocols/proto/dxos/mesh/swarm';
@@ -20,9 +20,9 @@ interface OfferRecord {
20
20
  }
21
21
 
22
22
  export type SwarmMessengerOptions = {
23
- sendMessage: (params: Message) => Promise<void>;
24
- onOffer: (message: OfferMessage) => Promise<Answer>;
25
- onSignal: (message: SignalMessage) => Promise<void>;
23
+ sendMessage: (ctx: Context, params: Message) => Promise<void>;
24
+ onOffer: (ctx: Context, message: OfferMessage) => Promise<Answer>;
25
+ onSignal: (ctx: Context, message: SignalMessage) => Promise<void>;
26
26
  topic: PublicKey;
27
27
  };
28
28
 
@@ -32,11 +32,9 @@ const SwarmMessage = schema.getCodecForType('dxos.mesh.swarm.SwarmMessage');
32
32
  * Adds offer/answer and signal interfaces.
33
33
  */
34
34
  export class SwarmMessenger implements SignalMessenger {
35
- private readonly _ctx = new Context();
36
-
37
- private readonly _sendMessage: (msg: Message) => Promise<void>;
38
- private readonly _onSignal: (message: SignalMessage) => Promise<void>;
39
- private readonly _onOffer: (message: OfferMessage) => Promise<Answer>;
35
+ private readonly _sendMessage: SwarmMessengerOptions['sendMessage'];
36
+ private readonly _onSignal: SwarmMessengerOptions['onSignal'];
37
+ private readonly _onOffer: SwarmMessengerOptions['onOffer'];
40
38
  private readonly _topic: PublicKey;
41
39
 
42
40
  private readonly _offerRecords: ComplexMap<PublicKey, OfferRecord> = new ComplexMap((key) => key.toHex());
@@ -48,15 +46,18 @@ export class SwarmMessenger implements SignalMessenger {
48
46
  this._topic = topic;
49
47
  }
50
48
 
51
- async receiveMessage({
52
- author,
53
- recipient,
54
- payload,
55
- }: {
56
- author: PeerInfo;
57
- recipient: PeerInfo;
58
- payload: Any;
59
- }): Promise<void> {
49
+ async receiveMessage(
50
+ ctx: Context,
51
+ {
52
+ author,
53
+ recipient,
54
+ payload,
55
+ }: {
56
+ author: PeerInfo;
57
+ recipient: PeerInfo;
58
+ payload: Any;
59
+ },
60
+ ): Promise<void> {
60
61
  if (payload.type_url !== 'dxos.mesh.swarm.SwarmMessage') {
61
62
  // Ignore not swarm messages.
62
63
  return;
@@ -71,35 +72,35 @@ export class SwarmMessenger implements SignalMessenger {
71
72
  log('received', { from: author, to: recipient, msg: message });
72
73
 
73
74
  if (message.data?.offer) {
74
- await this._handleOffer({ author, recipient, message });
75
+ await this._handleOffer(ctx, { author, recipient, message });
75
76
  } else if (message.data?.answer) {
76
77
  await this._resolveAnswers(message);
77
78
  } else if (message.data?.signal) {
78
- await this._handleSignal({ author, recipient, message });
79
+ await this._handleSignal(ctx, { author, recipient, message });
79
80
  } else if (message.data?.signalBatch) {
80
- await this._handleSignal({ author, recipient, message });
81
+ await this._handleSignal(ctx, { author, recipient, message });
81
82
  } else {
82
83
  log.warn('unknown message', { message });
83
84
  }
84
85
  }
85
86
 
86
- async signal(message: SignalMessage): Promise<void> {
87
+ async signal(ctx: Context, message: SignalMessage): Promise<void> {
87
88
  invariant(message.data?.signal || message.data?.signalBatch, 'Invalid message');
88
- await this._sendReliableMessage({
89
+ await this._sendReliableMessage(ctx, {
89
90
  author: message.author,
90
91
  recipient: message.recipient,
91
92
  message,
92
93
  });
93
94
  }
94
95
 
95
- async offer(message: OfferMessage): Promise<Answer> {
96
+ async offer(ctx: Context, message: OfferMessage): Promise<Answer> {
96
97
  const networkMessage: SwarmMessage = {
97
98
  ...message,
98
99
  messageId: PublicKey.random(),
99
100
  };
100
101
  return new Promise<Answer>((resolve, reject) => {
101
102
  this._offerRecords.set(networkMessage.messageId!, { resolve });
102
- this._sendReliableMessage({
103
+ this._sendReliableMessage(ctx, {
103
104
  author: message.author,
104
105
  recipient: message.recipient,
105
106
  message: networkMessage,
@@ -107,15 +108,18 @@ export class SwarmMessenger implements SignalMessenger {
107
108
  });
108
109
  }
109
110
 
110
- private async _sendReliableMessage({
111
- author,
112
- recipient,
113
- message,
114
- }: {
115
- author: PeerInfo;
116
- recipient: PeerInfo;
117
- message: MakeOptional<SwarmMessage, 'messageId'>;
118
- }): Promise<void> {
111
+ private async _sendReliableMessage(
112
+ ctx: Context,
113
+ {
114
+ author,
115
+ recipient,
116
+ message,
117
+ }: {
118
+ author: PeerInfo;
119
+ recipient: PeerInfo;
120
+ message: MakeOptional<SwarmMessage, 'messageId'>;
121
+ },
122
+ ): Promise<void> {
119
123
  const networkMessage: SwarmMessage = {
120
124
  ...message,
121
125
  // Setting unique message_id if it not specified yet.
@@ -123,7 +127,7 @@ export class SwarmMessenger implements SignalMessenger {
123
127
  };
124
128
 
125
129
  log('sending', { from: author, to: recipient, msg: networkMessage });
126
- await this._sendMessage({
130
+ await this._sendMessage(ctx, {
127
131
  author,
128
132
  recipient,
129
133
  payload: {
@@ -144,15 +148,18 @@ export class SwarmMessenger implements SignalMessenger {
144
148
  }
145
149
  }
146
150
 
147
- private async _handleOffer({
148
- author,
149
- recipient,
150
- message,
151
- }: {
152
- author: PeerInfo;
153
- recipient: PeerInfo;
154
- message: SwarmMessage;
155
- }): Promise<void> {
151
+ private async _handleOffer(
152
+ ctx: Context,
153
+ {
154
+ author,
155
+ recipient,
156
+ message,
157
+ }: {
158
+ author: PeerInfo;
159
+ recipient: PeerInfo;
160
+ message: SwarmMessage;
161
+ },
162
+ ): Promise<void> {
156
163
  invariant(message.data.offer, 'No offer');
157
164
  const offerMessage: OfferMessage = {
158
165
  author,
@@ -160,10 +167,10 @@ export class SwarmMessenger implements SignalMessenger {
160
167
  ...message,
161
168
  data: { offer: message.data.offer },
162
169
  };
163
- const answer = await this._onOffer(offerMessage);
170
+ const answer = await this._onOffer(ctx, offerMessage);
164
171
  answer.offerMessageId = message.messageId;
165
172
  try {
166
- await this._sendReliableMessage({
173
+ await this._sendReliableMessage(ctx, {
167
174
  author: recipient,
168
175
  recipient: author,
169
176
  message: {
@@ -181,15 +188,18 @@ export class SwarmMessenger implements SignalMessenger {
181
188
  }
182
189
  }
183
190
 
184
- private async _handleSignal({
185
- author,
186
- recipient,
187
- message,
188
- }: {
189
- author: PeerInfo;
190
- recipient: PeerInfo;
191
- message: SwarmMessage;
192
- }): Promise<void> {
191
+ private async _handleSignal(
192
+ ctx: Context,
193
+ {
194
+ author,
195
+ recipient,
196
+ message,
197
+ }: {
198
+ author: PeerInfo;
199
+ recipient: PeerInfo;
200
+ message: SwarmMessage;
201
+ },
202
+ ): Promise<void> {
193
203
  invariant(message.messageId);
194
204
  invariant(message.data.signal || message.data.signalBatch, 'Invalid message');
195
205
  const signalMessage: SignalMessage = {
@@ -202,6 +212,6 @@ export class SwarmMessenger implements SignalMessenger {
202
212
  },
203
213
  };
204
214
 
205
- await this._onSignal(signalMessage);
215
+ await this._onSignal(ctx, signalMessage);
206
216
  }
207
217
  }
@@ -7,12 +7,13 @@ import { describe, test } from 'vitest';
7
7
  import { sleep } from '@dxos/async';
8
8
  import { PublicKey } from '@dxos/keys';
9
9
 
10
- import { Connection } from './connection';
11
10
  import { TestWireProtocol } from '../testing/test-wire-protocol';
12
11
  import { createRtcTransportFactory } from '../transport';
13
12
  import { chooseInitiatorPeer } from '../transport/webrtc/utils';
13
+ import { Connection } from './connection';
14
14
 
15
- describe('Connection', () => {
15
+ // Segfault in node-datachannel.
16
+ describe.skip('Connection', () => {
16
17
  test('responder opens after initiator', async () => {
17
18
  const { initiator, responder } = createPeerKeys();
18
19
  await connectionTest({
@@ -42,9 +43,9 @@ describe('Connection', () => {
42
43
  sessionId,
43
44
  true,
44
45
  {
45
- offer: async (msg) => ({ accept: true }),
46
- signal: async (msg) => {
47
- await fastConnection.signal(msg);
46
+ offer: async (_ctx, _msg) => ({ accept: true }),
47
+ signal: async (ctx, msg) => {
48
+ await fastConnection.signal(ctx, msg);
48
49
  },
49
50
  },
50
51
  slowPeerProtocol.factory({
@@ -64,9 +65,9 @@ describe('Connection', () => {
64
65
  sessionId,
65
66
  false,
66
67
  {
67
- offer: async (msg) => ({ accept: true }),
68
- signal: async (msg) => {
69
- await slowConnection.signal(msg);
68
+ offer: async (_ctx, _msg) => ({ accept: true }),
69
+ signal: async (ctx, msg) => {
70
+ await slowConnection.signal(ctx, msg);
70
71
  },
71
72
  },
72
73
  fastPeerProtocol.factory({
@@ -2,21 +2,14 @@
2
2
  // Copyright 2021 DXOS.org
3
3
  //
4
4
 
5
- import { DeferredTask, Event, sleep, scheduleTask, scheduleTaskInterval, synchronized, Trigger } from '@dxos/async';
6
- import { Context, cancelWithContext, ContextDisposedError } from '@dxos/context';
5
+ import { DeferredTask, Event, Trigger, scheduleTask, scheduleTaskInterval, sleep, synchronized } from '@dxos/async';
6
+ import { Context, ContextDisposedError, cancelWithContext } from '@dxos/context';
7
7
  import { ErrorStream } from '@dxos/debug';
8
8
  import { invariant } from '@dxos/invariant';
9
9
  import { PublicKey } from '@dxos/keys';
10
10
  import { log, logInfo } from '@dxos/log';
11
11
  import { type PeerInfo } from '@dxos/messaging';
12
- import {
13
- CancelledError,
14
- ProtocolError,
15
- ConnectionResetError,
16
- ConnectivityError,
17
- TimeoutError,
18
- trace,
19
- } from '@dxos/protocols';
12
+ import { CancelledError, ConnectionResetError, ConnectivityError, ProtocolError, TimeoutError } from '@dxos/protocols';
20
13
  import { type Signal } from '@dxos/protocols/proto/dxos/mesh/swarm';
21
14
 
22
15
  import { type SignalMessage, type SignalMessenger } from '../signal';
@@ -113,12 +106,10 @@ export class Connection {
113
106
  readonly stateChanged = new Event<ConnectionState>();
114
107
  readonly errors = new ErrorStream();
115
108
 
116
- public _instanceId = PublicKey.random().toHex();
117
-
118
109
  public readonly transportStats = new Event<TransportStats>();
119
110
 
120
111
  private readonly _signalSendTask = new DeferredTask(this._ctx, async () => {
121
- await this._flushSignalBuffer();
112
+ await this._flushSignalBuffer(this._ctx);
122
113
  });
123
114
 
124
115
  private _signallingDelay = STARTING_SIGNALLING_DELAY;
@@ -165,7 +156,7 @@ export class Connection {
165
156
  */
166
157
  async openConnection(): Promise<void> {
167
158
  invariant(this._state === ConnectionState.INITIAL, 'Invalid state.');
168
- log.trace('dxos.mesh.connection.open-connection', trace.begin({ id: this._instanceId }));
159
+ log('opening connection');
169
160
  log.trace('dxos.mesh.connection.open', {
170
161
  sessionId: this.sessionId,
171
162
  topic: this.topic,
@@ -185,16 +176,18 @@ export class Connection {
185
176
  this._protocol.stream.on('close', () => {
186
177
  log('protocol stream closed');
187
178
  this._protocolClosed.wake();
188
- this.close({ error: new ProtocolError('protocol stream closed') }).catch((err) => this.errors.raise(err));
179
+ this.close({ error: new ProtocolError({ message: 'protocol stream closed' }) }).catch((err) =>
180
+ this.errors.raise(err),
181
+ );
189
182
  });
190
183
 
191
184
  scheduleTask(
192
185
  this.connectedTimeoutContext,
193
186
  async () => {
194
187
  log.info(`timeout waiting ${TRANSPORT_CONNECTION_TIMEOUT / 1000}s for transport to connect, aborting`);
195
- await this.abort(new TimeoutError(`${TRANSPORT_CONNECTION_TIMEOUT / 1000}s for transport to connect`)).catch(
196
- (err) => this.errors.raise(err),
197
- );
188
+ await this.abort(
189
+ new TimeoutError({ message: `${TRANSPORT_CONNECTION_TIMEOUT / 1000}s for transport to connect` }),
190
+ ).catch((err) => this.errors.raise(err));
198
191
  },
199
192
  TRANSPORT_CONNECTION_TIMEOUT,
200
193
  );
@@ -255,7 +248,7 @@ export class Connection {
255
248
 
256
249
  this._incomingSignalBuffer = [];
257
250
 
258
- log.trace('dxos.mesh.connection.open-connection', trace.end({ id: this._instanceId }));
251
+ log('opened connection');
259
252
  }
260
253
 
261
254
  @synchronized
@@ -364,21 +357,21 @@ export class Connection {
364
357
  this._signalSendTask.schedule();
365
358
  }
366
359
 
367
- private async _flushSignalBuffer(): Promise<void> {
360
+ private async _flushSignalBuffer(ctx: Context): Promise<void> {
368
361
  if (this._outgoingSignalBuffer.length === 0) {
369
362
  return;
370
363
  }
371
364
 
372
365
  try {
373
366
  if (process.env.NODE_ENV !== 'test') {
374
- await cancelWithContext(this._ctx, sleep(this._signallingDelay));
367
+ await cancelWithContext(ctx, sleep(this._signallingDelay));
375
368
  this._signallingDelay = Math.min(this._signallingDelay * 2, MAX_SIGNALLING_DELAY);
376
369
  }
377
370
 
378
371
  const signals = [...this._outgoingSignalBuffer];
379
372
  this._outgoingSignalBuffer.length = 0;
380
373
 
381
- await this._signalMessaging.signal({
374
+ await this._signalMessaging.signal(ctx, {
382
375
  author: this.localInfo,
383
376
  recipient: this.remoteInfo,
384
377
  sessionId: this.sessionId,
@@ -397,14 +390,14 @@ export class Connection {
397
390
 
398
391
  // If signal fails treat connection as failed
399
392
  log.info('signal message failed to deliver', { err });
400
- await this.close({ error: new ConnectivityError('signal message failed to deliver', err) });
393
+ await this.close({ error: new ConnectivityError({ message: 'signal message failed to deliver', cause: err }) });
401
394
  }
402
395
  }
403
396
 
404
397
  /**
405
398
  * Receive a signal from the remote peer.
406
399
  */
407
- async signal(msg: SignalMessage): Promise<void> {
400
+ async signal(_ctx: Context, msg: SignalMessage): Promise<void> {
408
401
  invariant(msg.sessionId);
409
402
  if (!msg.sessionId.equals(this.sessionId)) {
410
403
  log('dropping signal for incorrect session id');
@@ -414,7 +407,7 @@ export class Connection {
414
407
  invariant(msg.author.peerKey === this.remoteInfo.peerKey);
415
408
  invariant(msg.recipient.peerKey === this.localInfo.peerKey);
416
409
 
417
- const signals = msg.data.signalBatch ? msg.data.signalBatch.signals ?? [] : [msg.data.signal];
410
+ const signals = msg.data.signalBatch ? (msg.data.signalBatch.signals ?? []) : [msg.data.signal];
418
411
  for (const signal of signals) {
419
412
  if (!signal) {
420
413
  continue;
package/src/swarm/peer.ts CHANGED
@@ -11,15 +11,15 @@ import { type PeerInfo } from '@dxos/messaging';
11
11
  import { CancelledError, SystemError } from '@dxos/protocols';
12
12
  import { type Answer } from '@dxos/protocols/proto/dxos/mesh/swarm';
13
13
 
14
- import { Connection, ConnectionState } from './connection';
15
- import { type ConnectionLimiter } from './connection-limiter';
16
14
  import { type OfferMessage, type SignalMessage, type SignalMessenger } from '../signal';
17
15
  import { type TransportFactory } from '../transport';
18
16
  import { type WireProtocolProvider } from '../wire-protocol';
17
+ import { Connection, ConnectionState } from './connection';
18
+ import { type ConnectionLimiter } from './connection-limiter';
19
19
 
20
20
  export class ConnectionDisplacedError extends SystemError {
21
21
  constructor() {
22
- super('Connection displaced by remote initiator.');
22
+ super({ message: 'Connection displaced by remote initiator.' });
23
23
  }
24
24
  }
25
25
 
@@ -105,7 +105,7 @@ export class Peer {
105
105
  /**
106
106
  * Respond to remote offer.
107
107
  */
108
- async onOffer(message: OfferMessage): Promise<Answer> {
108
+ async onOffer(_ctx: Context, message: OfferMessage): Promise<Answer> {
109
109
  const remote = message.author;
110
110
 
111
111
  if (
@@ -161,13 +161,14 @@ export class Peer {
161
161
  return { accept: true };
162
162
  }
163
163
  }
164
+
164
165
  return { accept: false };
165
166
  }
166
167
 
167
168
  /**
168
169
  * Initiate a connection to the remote peer.
169
170
  */
170
- async initiateConnection(): Promise<void> {
171
+ async initiateConnection(ctx: Context): Promise<void> {
171
172
  invariant(!this.initiating, 'Initiation in progress.');
172
173
  invariant(!this.connection, 'Already connected.');
173
174
  const sessionId = PublicKey.random();
@@ -181,7 +182,7 @@ export class Peer {
181
182
  await this._connectionLimiter.connecting(sessionId);
182
183
  connection.initiate();
183
184
 
184
- answer = await this._signalMessaging.offer({
185
+ answer = await this._signalMessaging.offer(ctx, {
185
186
  author: this.localInfo,
186
187
  recipient: this.remoteInfo,
187
188
  sessionId,
@@ -376,13 +377,13 @@ export class Peer {
376
377
  log('closed', { peerId: this.remoteInfo, sessionId: connection.sessionId });
377
378
  }
378
379
 
379
- async onSignal(message: SignalMessage): Promise<void> {
380
+ async onSignal(ctx: Context, message: SignalMessage): Promise<void> {
380
381
  if (!this.connection) {
381
382
  log('dropping signal message for non-existent connection', { message });
382
383
  return;
383
384
  }
384
385
 
385
- await this.connection.signal(message);
386
+ await this.connection.signal(ctx, message);
386
387
  }
387
388
 
388
389
  @synchronized
@@ -5,7 +5,7 @@
5
5
  import { type CleanupFn, Event, SubscriptionList } from '@dxos/async';
6
6
  import { PublicKey } from '@dxos/keys';
7
7
  import { log } from '@dxos/log';
8
- import { PeerInfoHash, type PeerInfo as MessagingPeer } from '@dxos/messaging';
8
+ import { type PeerInfo as MessagingPeer, PeerInfoHash } from '@dxos/messaging';
9
9
  import { ComplexMap } from '@dxos/util';
10
10
 
11
11
  import { type ConnectionState } from './connection';
@@ -2,7 +2,7 @@
2
2
  // Copyright 2020 DXOS.org
3
3
  //
4
4
 
5
- import { onTestFinished, describe, expect, test } from 'vitest';
5
+ import { describe, expect, onTestFinished, test } from 'vitest';
6
6
 
7
7
  import { asyncTimeout, sleep } from '@dxos/async';
8
8
  import { PublicKey } from '@dxos/keys';
@@ -15,12 +15,12 @@ import {
15
15
  } from '@dxos/messaging';
16
16
  import { ComplexSet } from '@dxos/util';
17
17
 
18
- import { ConnectionState } from './connection';
19
- import { ConnectionLimiter } from './connection-limiter';
20
- import { Swarm } from './swarm';
21
18
  import { TestWireProtocol } from '../testing/test-wire-protocol';
22
19
  import { FullyConnectedTopology } from '../topology';
23
20
  import { createRtcTransportFactory } from '../transport';
21
+ import { ConnectionState } from './connection';
22
+ import { ConnectionLimiter } from './connection-limiter';
23
+ import { Swarm } from './swarm';
24
24
 
25
25
  type TestPeer = {
26
26
  swarm: Swarm;
@@ -30,7 +30,8 @@ type TestPeer = {
30
30
  signalManager: SignalManager;
31
31
  };
32
32
 
33
- describe('Swarm', () => {
33
+ // Segfault in node-datachannel.
34
+ describe.skip('Swarm', () => {
34
35
  const context = new MemorySignalManagerContext();
35
36
 
36
37
  const setupSwarm = async ({
@@ -157,9 +158,9 @@ describe('Swarm', () => {
157
158
  const messages = new ComplexSet<{ author: PeerInfo; recipient: PeerInfo }>(
158
159
  ({ author, recipient }) => author.peerKey + recipient.peerKey,
159
160
  );
160
- signalManager.sendMessage = async (message) => {
161
+ signalManager.sendMessage = async (ctx, message) => {
161
162
  messages.add({ author: message.author, recipient: message.recipient });
162
- return sendOriginal(message);
163
+ return sendOriginal(ctx, message);
163
164
  };
164
165
  // Stop signaling to stop connection in initiation state.
165
166
  signalManager.freeze();
@@ -8,19 +8,18 @@ import { ErrorStream } from '@dxos/debug';
8
8
  import { invariant } from '@dxos/invariant';
9
9
  import { PublicKey } from '@dxos/keys';
10
10
  import { log, logInfo } from '@dxos/log';
11
- import { type SwarmEvent, type ListeningHandle, type Messenger, type PeerInfo, PeerInfoHash } from '@dxos/messaging';
12
- import { trace } from '@dxos/protocols';
11
+ import { type ListeningHandle, type Messenger, type PeerInfo, PeerInfoHash, type SwarmEvent } from '@dxos/messaging';
13
12
  import { type Answer } from '@dxos/protocols/proto/dxos/mesh/swarm';
14
13
  import { ComplexMap, isNonNullable } from '@dxos/util';
15
14
 
16
- import { type Connection, ConnectionState } from './connection';
17
- import { type ConnectionLimiter } from './connection-limiter';
18
- import { Peer } from './peer';
19
15
  import { type OfferMessage, type SignalMessage, SwarmMessenger } from '../signal';
20
16
  import { type SwarmController, type Topology } from '../topology';
21
17
  import { type TransportFactory } from '../transport';
22
18
  import { type Topic } from '../types';
23
19
  import { type WireProtocolProvider } from '../wire-protocol';
20
+ import { type Connection, ConnectionState } from './connection';
21
+ import { type ConnectionLimiter } from './connection-limiter';
22
+ import { Peer } from './peer';
24
23
 
25
24
  const INITIATION_DELAY = 100;
26
25
 
@@ -85,20 +84,15 @@ export class Swarm {
85
84
  private readonly _connectionLimiter: ConnectionLimiter,
86
85
  private readonly _initiationDelay = INITIATION_DELAY,
87
86
  ) {
88
- log.trace(
89
- 'dxos.mesh.swarm.constructor',
90
- trace.begin({ id: this._instanceId, data: { topic: this._topic.toHex(), peer: this._ownPeer } }),
91
- );
92
- log('creating swarm', { peerId: _ownPeer });
87
+ log('creating swarm', { topic: this._topic.toHex(), peer: this._ownPeer });
93
88
  _topology.init(this._getSwarmController());
94
89
 
95
90
  this._swarmMessenger = new SwarmMessenger({
96
- sendMessage: async (msg) => await this._messenger.sendMessage(msg),
97
- onSignal: async (msg) => await this.onSignal(msg),
98
- onOffer: async (msg) => await this.onOffer(msg),
91
+ sendMessage: async (ctx, msg) => await this._messenger.sendMessage(ctx, msg),
92
+ onSignal: async (ctx, msg) => await this.onSignal(ctx, msg),
93
+ onOffer: async (ctx, msg) => await this.onOffer(ctx, msg),
99
94
  topic: this._topic,
100
95
  });
101
- log.trace('dxos.mesh.swarm.constructor', trace.end({ id: this._instanceId }));
102
96
  }
103
97
 
104
98
  get connections() {
@@ -135,7 +129,7 @@ export class Swarm {
135
129
  payloadType: 'dxos.mesh.swarm.SwarmMessage',
136
130
  onMessage: async (message) => {
137
131
  await this._swarmMessenger
138
- .receiveMessage(message)
132
+ .receiveMessage(this._ctx, message)
139
133
  // TODO(nf): discriminate between errors
140
134
  .catch((err) => log.info('Error while receiving message', { err }));
141
135
  },
@@ -204,7 +198,7 @@ export class Swarm {
204
198
  }
205
199
 
206
200
  @synchronized
207
- async onOffer(message: OfferMessage): Promise<Answer> {
201
+ async onOffer(ctx: Context, message: OfferMessage): Promise<Answer> {
208
202
  log('offer', { message });
209
203
  if (this._ctx.disposed) {
210
204
  log('ignored for disposed swarm');
@@ -223,7 +217,7 @@ export class Swarm {
223
217
  }
224
218
 
225
219
  const peer = this._getOfferSenderPeer(message.author);
226
- const answer = await peer.onOffer(message);
220
+ const answer = await peer.onOffer(ctx, message);
227
221
  this._topology.update();
228
222
  return answer;
229
223
  }
@@ -242,7 +236,7 @@ export class Swarm {
242
236
  return peer;
243
237
  }
244
238
 
245
- async onSignal(message: SignalMessage): Promise<void> {
239
+ async onSignal(ctx: Context, message: SignalMessage): Promise<void> {
246
240
  log('signal', { message });
247
241
  if (this._ctx.disposed) {
248
242
  log.info('ignored for offline swarm');
@@ -256,7 +250,7 @@ export class Swarm {
256
250
  invariant(message.author);
257
251
 
258
252
  const peer = this._getOrCreatePeer(message.author);
259
- await peer.onSignal(message);
253
+ await peer.onSignal(ctx, message);
260
254
  }
261
255
 
262
256
  // For debug purposes
@@ -403,7 +397,7 @@ export class Swarm {
403
397
  }
404
398
 
405
399
  log('initiating connection...', { remotePeer });
406
- await peer.initiateConnection();
400
+ await peer.initiateConnection(ctx);
407
401
  this._topology.update();
408
402
  log('initiated', { remotePeer });
409
403
  }
@@ -2,6 +2,7 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
+ import { Context } from '@dxos/context';
5
6
  import { PublicKey } from '@dxos/keys';
6
7
  import { log } from '@dxos/log';
7
8
  import {
@@ -13,15 +14,22 @@ import {
13
14
  import { schema } from '@dxos/protocols/proto';
14
15
  import { ConnectionState } from '@dxos/protocols/proto/dxos/client/services';
15
16
  import { type Runtime } from '@dxos/protocols/proto/dxos/config';
16
- import { createLinkedPorts, createProtoRpcPeer, type ProtoRpcPeer } from '@dxos/rpc';
17
+ import { type ProtoRpcPeer, createLinkedPorts, createProtoRpcPeer } from '@dxos/rpc';
17
18
  import { ComplexMap } from '@dxos/util';
18
19
 
19
20
  import { TcpTransportFactory } from '#tcp-transport';
20
- import { type TestTeleportExtensionFactory, TestWireProtocol } from './test-wire-protocol';
21
+
21
22
  import { SwarmNetworkManager } from '../network-manager';
22
23
  import { FullyConnectedTopology } from '../topology';
23
- import { MemoryTransportFactory, type TransportFactory, TransportKind } from '../transport';
24
- import { createRtcTransportFactory, RtcTransportProxyFactory, RtcTransportService } from '../transport';
24
+ import {
25
+ MemoryTransportFactory,
26
+ RtcTransportProxyFactory,
27
+ RtcTransportService,
28
+ type TransportFactory,
29
+ TransportKind,
30
+ createRtcTransportFactory,
31
+ } from '../transport';
32
+ import { type TestTeleportExtensionFactory, TestWireProtocol } from './test-wire-protocol';
25
33
 
26
34
  // Signal server will be started by the setup script.
27
35
  const port = process.env.SIGNAL_PORT ?? 4000;
@@ -161,7 +169,7 @@ export class TestPeer {
161
169
 
162
170
  await this._proxy?.close();
163
171
  await this._service?.close();
164
- await this._networkManager.close();
172
+ await this._networkManager.close(Context.default());
165
173
  }
166
174
 
167
175
  getSwarm(topic: PublicKey): TestSwarmConnection {
@@ -210,7 +218,7 @@ export class TestSwarmConnection {
210
218
  // TODO(burdon): Need to create new plugin instance per swarm?
211
219
  // If so, then perhaps joinSwarm should return swarm object with access to plugins.
212
220
  async join(topology = new FullyConnectedTopology()): Promise<this> {
213
- await this.peer._networkManager.joinSwarm({
221
+ await this.peer._networkManager.joinSwarm(Context.default(), {
214
222
  topic: this.topic,
215
223
  peerInfo: { peerKey: this.peer.peerId.toHex(), identityKey: this.peer.peerId.toHex() },
216
224
  protocolProvider: this.protocol.factory,
@@ -221,7 +229,7 @@ export class TestSwarmConnection {
221
229
  }
222
230
 
223
231
  async leave(): Promise<this> {
224
- await this.peer._networkManager.leaveSwarm(this.topic);
232
+ await this.peer._networkManager.leaveSwarm(Context.default(), this.topic);
225
233
  return this;
226
234
  }
227
235
  }