@dxos/network-manager 0.6.12-staging.e11e696 → 0.6.12

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 (155) hide show
  1. package/dist/lib/browser/{chunk-YOKKEU6T.mjs → chunk-XYSYUN63.mjs} +998 -1192
  2. package/dist/lib/browser/chunk-XYSYUN63.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +19 -10
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/browser/testing/index.mjs +27 -18
  6. package/dist/lib/browser/testing/index.mjs.map +3 -3
  7. package/dist/lib/node/{chunk-7ZWQLO5T.cjs → chunk-4YAYC7WN.cjs} +1166 -1233
  8. package/dist/lib/node/chunk-4YAYC7WN.cjs.map +7 -0
  9. package/dist/lib/node/index.cjs +37 -27
  10. package/dist/lib/node/index.cjs.map +2 -2
  11. package/dist/lib/node/meta.json +1 -1
  12. package/dist/lib/node/testing/index.cjs +29 -20
  13. package/dist/lib/node/testing/index.cjs.map +3 -3
  14. package/dist/types/src/signal/integration.test.d.ts +2 -0
  15. package/dist/types/src/signal/integration.test.d.ts.map +1 -0
  16. package/dist/types/src/signal/swarm-messenger.test.d.ts +2 -0
  17. package/dist/types/src/signal/swarm-messenger.test.d.ts.map +1 -0
  18. package/dist/types/src/swarm/connection.d.ts.map +1 -1
  19. package/dist/types/src/swarm/swarm.d.ts +1 -1
  20. package/dist/types/src/testing/test-builder.d.ts +2 -2
  21. package/dist/types/src/testing/test-builder.d.ts.map +1 -1
  22. package/dist/types/src/tests/basic-test-suite.d.ts.map +1 -1
  23. package/dist/types/src/tests/property-test-suite.d.ts.map +1 -1
  24. package/dist/types/src/tests/tcp-transport.test.d.ts +2 -0
  25. package/dist/types/src/tests/tcp-transport.test.d.ts.map +1 -0
  26. package/dist/types/src/tests/utils.d.ts.map +1 -1
  27. package/dist/types/src/transport/index.d.ts +5 -1
  28. package/dist/types/src/transport/index.d.ts.map +1 -1
  29. package/dist/types/src/transport/libdatachannel-transport.d.ts +42 -0
  30. package/dist/types/src/transport/libdatachannel-transport.d.ts.map +1 -0
  31. package/dist/types/src/transport/libdatachannel-transport.test.d.ts +2 -0
  32. package/dist/types/src/transport/libdatachannel-transport.test.d.ts.map +1 -0
  33. package/dist/types/src/transport/memory-transport.d.ts +2 -2
  34. package/dist/types/src/transport/memory-transport.d.ts.map +1 -1
  35. package/dist/types/src/transport/memory-transport.test.d.ts +2 -0
  36. package/dist/types/src/transport/memory-transport.test.d.ts.map +1 -0
  37. package/dist/types/src/transport/simplepeer-simple-peer.d.ts +2 -0
  38. package/dist/types/src/transport/simplepeer-simple-peer.d.ts.map +1 -0
  39. package/dist/types/src/transport/simplepeer-transport-proxy-test.d.ts +2 -0
  40. package/dist/types/src/transport/simplepeer-transport-proxy-test.d.ts.map +1 -0
  41. package/dist/types/src/transport/{webrtc/rtc-transport-proxy.d.ts → simplepeer-transport-proxy.d.ts} +12 -10
  42. package/dist/types/src/transport/simplepeer-transport-proxy.d.ts.map +1 -0
  43. package/dist/types/src/transport/{webrtc/rtc-transport-service.d.ts → simplepeer-transport-service.d.ts} +7 -9
  44. package/dist/types/src/transport/simplepeer-transport-service.d.ts.map +1 -0
  45. package/dist/types/src/transport/simplepeer-transport.d.ts +36 -0
  46. package/dist/types/src/transport/simplepeer-transport.d.ts.map +1 -0
  47. package/dist/types/src/transport/simplepeer-transport.test.d.ts +2 -0
  48. package/dist/types/src/transport/simplepeer-transport.test.d.ts.map +1 -0
  49. package/dist/types/src/transport/{tcp/tcp-transport.browser.d.ts → tcp-transport.browser.d.ts} +3 -3
  50. package/dist/types/src/transport/tcp-transport.browser.d.ts.map +1 -0
  51. package/dist/types/src/transport/{tcp/tcp-transport.d.ts → tcp-transport.d.ts} +3 -3
  52. package/dist/types/src/transport/tcp-transport.d.ts.map +1 -0
  53. package/dist/types/src/transport/transport.d.ts +6 -7
  54. package/dist/types/src/transport/transport.d.ts.map +1 -1
  55. package/dist/types/src/transport/webrtc.d.ts +6 -0
  56. package/dist/types/src/transport/webrtc.d.ts.map +1 -0
  57. package/package.json +30 -53
  58. package/src/globals.d.ts +7 -0
  59. package/src/signal/ice.test.ts +3 -1
  60. package/src/signal/{integration.node.test.ts → integration.test.ts} +15 -9
  61. package/src/signal/{swarm-messenger.node.test.ts → swarm-messenger.test.ts} +23 -13
  62. package/src/swarm/connection-limiter.test.ts +6 -3
  63. package/src/swarm/connection.test.ts +38 -63
  64. package/src/swarm/connection.ts +5 -5
  65. package/src/swarm/swarm.test.ts +11 -9
  66. package/src/swarm/swarm.ts +1 -1
  67. package/src/testing/test-builder.ts +28 -12
  68. package/src/tests/basic-test-suite.ts +33 -34
  69. package/src/tests/memory-transport.test.ts +42 -40
  70. package/src/tests/property-test-suite.ts +22 -21
  71. package/src/tests/tcp-transport.test.ts +67 -0
  72. package/src/tests/utils.ts +2 -3
  73. package/src/tests/webrtc-transport.test.ts +9 -9
  74. package/src/transport/index.ts +5 -1
  75. package/src/transport/libdatachannel-transport.test.ts +100 -0
  76. package/src/transport/libdatachannel-transport.ts +376 -0
  77. package/src/transport/memory-transport.test.ts +74 -0
  78. package/src/transport/memory-transport.ts +0 -2
  79. package/src/transport/simplepeer-simple-peer.ts +26 -0
  80. package/src/transport/simplepeer-transport-proxy-test.ts +181 -0
  81. package/src/transport/simplepeer-transport-proxy.ts +246 -0
  82. package/src/transport/simplepeer-transport-service.ts +160 -0
  83. package/src/transport/simplepeer-transport.test.ts +61 -0
  84. package/src/transport/simplepeer-transport.ts +250 -0
  85. package/src/transport/{tcp/tcp-transport.browser.ts → tcp-transport.browser.ts} +3 -7
  86. package/src/transport/{tcp/tcp-transport.ts → tcp-transport.ts} +1 -3
  87. package/src/transport/transport.ts +7 -8
  88. package/src/transport/webrtc.ts +15 -0
  89. package/src/typings.d.ts +2 -8
  90. package/dist/lib/browser/chunk-GW3YM55A.mjs +0 -14
  91. package/dist/lib/browser/chunk-GW3YM55A.mjs.map +0 -7
  92. package/dist/lib/browser/chunk-YOKKEU6T.mjs.map +0 -7
  93. package/dist/lib/browser/transport/tcp/index.mjs +0 -39
  94. package/dist/lib/browser/transport/tcp/index.mjs.map +0 -7
  95. package/dist/lib/node/chunk-7ZWQLO5T.cjs.map +0 -7
  96. package/dist/lib/node/transport/tcp/index.cjs +0 -191
  97. package/dist/lib/node/transport/tcp/index.cjs.map +0 -7
  98. package/dist/lib/node-esm/chunk-4VO725JT.mjs +0 -4383
  99. package/dist/lib/node-esm/chunk-4VO725JT.mjs.map +0 -7
  100. package/dist/lib/node-esm/index.mjs +0 -50
  101. package/dist/lib/node-esm/index.mjs.map +0 -7
  102. package/dist/lib/node-esm/meta.json +0 -1
  103. package/dist/lib/node-esm/testing/index.mjs +0 -280
  104. package/dist/lib/node-esm/testing/index.mjs.map +0 -7
  105. package/dist/lib/node-esm/transport/tcp/index.mjs +0 -159
  106. package/dist/lib/node-esm/transport/tcp/index.mjs.map +0 -7
  107. package/dist/types/src/signal/integration.node.test.d.ts +0 -2
  108. package/dist/types/src/signal/integration.node.test.d.ts.map +0 -1
  109. package/dist/types/src/signal/swarm-messenger.node.test.d.ts +0 -2
  110. package/dist/types/src/signal/swarm-messenger.node.test.d.ts.map +0 -1
  111. package/dist/types/src/tests/tcp-transport.node.test.d.ts +0 -2
  112. package/dist/types/src/tests/tcp-transport.node.test.d.ts.map +0 -1
  113. package/dist/types/src/transport/tcp/index.d.ts +0 -2
  114. package/dist/types/src/transport/tcp/index.d.ts.map +0 -1
  115. package/dist/types/src/transport/tcp/tcp-transport.browser.d.ts.map +0 -1
  116. package/dist/types/src/transport/tcp/tcp-transport.d.ts.map +0 -1
  117. package/dist/types/src/transport/webrtc/index.d.ts +0 -4
  118. package/dist/types/src/transport/webrtc/index.d.ts.map +0 -1
  119. package/dist/types/src/transport/webrtc/rtc-connection-factory.d.ts +0 -14
  120. package/dist/types/src/transport/webrtc/rtc-connection-factory.d.ts.map +0 -1
  121. package/dist/types/src/transport/webrtc/rtc-peer-connection.d.ts +0 -68
  122. package/dist/types/src/transport/webrtc/rtc-peer-connection.d.ts.map +0 -1
  123. package/dist/types/src/transport/webrtc/rtc-transport-channel.d.ts +0 -33
  124. package/dist/types/src/transport/webrtc/rtc-transport-channel.d.ts.map +0 -1
  125. package/dist/types/src/transport/webrtc/rtc-transport-channel.test.d.ts +0 -2
  126. package/dist/types/src/transport/webrtc/rtc-transport-channel.test.d.ts.map +0 -1
  127. package/dist/types/src/transport/webrtc/rtc-transport-factory.d.ts +0 -4
  128. package/dist/types/src/transport/webrtc/rtc-transport-factory.d.ts.map +0 -1
  129. package/dist/types/src/transport/webrtc/rtc-transport-proxy.d.ts.map +0 -1
  130. package/dist/types/src/transport/webrtc/rtc-transport-proxy.test.d.ts +0 -2
  131. package/dist/types/src/transport/webrtc/rtc-transport-proxy.test.d.ts.map +0 -1
  132. package/dist/types/src/transport/webrtc/rtc-transport-service.d.ts.map +0 -1
  133. package/dist/types/src/transport/webrtc/rtc-transport-stats.d.ts +0 -4
  134. package/dist/types/src/transport/webrtc/rtc-transport-stats.d.ts.map +0 -1
  135. package/dist/types/src/transport/webrtc/rtc-transport.test.d.ts +0 -2
  136. package/dist/types/src/transport/webrtc/rtc-transport.test.d.ts.map +0 -1
  137. package/dist/types/src/transport/webrtc/test-utils.d.ts +0 -5
  138. package/dist/types/src/transport/webrtc/test-utils.d.ts.map +0 -1
  139. package/dist/types/src/transport/webrtc/utils.d.ts +0 -3
  140. package/dist/types/src/transport/webrtc/utils.d.ts.map +0 -1
  141. package/src/tests/tcp-transport.node.test.ts +0 -65
  142. package/src/transport/tcp/index.ts +0 -5
  143. package/src/transport/webrtc/index.ts +0 -7
  144. package/src/transport/webrtc/rtc-connection-factory.ts +0 -82
  145. package/src/transport/webrtc/rtc-peer-connection.ts +0 -472
  146. package/src/transport/webrtc/rtc-transport-channel.test.ts +0 -176
  147. package/src/transport/webrtc/rtc-transport-channel.ts +0 -195
  148. package/src/transport/webrtc/rtc-transport-factory.ts +0 -28
  149. package/src/transport/webrtc/rtc-transport-proxy.test.ts +0 -413
  150. package/src/transport/webrtc/rtc-transport-proxy.ts +0 -264
  151. package/src/transport/webrtc/rtc-transport-service.ts +0 -192
  152. package/src/transport/webrtc/rtc-transport-stats.ts +0 -67
  153. package/src/transport/webrtc/rtc-transport.test.ts +0 -198
  154. package/src/transport/webrtc/test-utils.ts +0 -22
  155. package/src/transport/webrtc/utils.ts +0 -36
@@ -1,4383 +0,0 @@
1
- import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
2
-
3
- // packages/core/mesh/network-manager/src/swarm/connection.ts
4
- import { DeferredTask, Event, sleep, scheduleTask, scheduleTaskInterval, synchronized, Trigger } from "@dxos/async";
5
- import { Context, cancelWithContext, ContextDisposedError } from "@dxos/context";
6
- import { ErrorStream } from "@dxos/debug";
7
- import { invariant } from "@dxos/invariant";
8
- import { PublicKey } from "@dxos/keys";
9
- import { log, logInfo } from "@dxos/log";
10
- import { CancelledError, ProtocolError, ConnectionResetError, ConnectivityError, TimeoutError, trace } from "@dxos/protocols";
11
- function _ts_decorate(decorators, target, key, desc) {
12
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
13
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
14
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
15
- return c > 3 && r && Object.defineProperty(target, key, r), r;
16
- }
17
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/swarm/connection.ts";
18
- var STARTING_SIGNALLING_DELAY = 10;
19
- var TRANSPORT_CONNECTION_TIMEOUT = 1e4;
20
- var TRANSPORT_STATS_INTERVAL = 5e3;
21
- var MAX_SIGNALLING_DELAY = 300;
22
- var ConnectionState;
23
- (function(ConnectionState5) {
24
- ConnectionState5["CREATED"] = "CREATED";
25
- ConnectionState5["INITIAL"] = "INITIAL";
26
- ConnectionState5["CONNECTING"] = "CONNECTING";
27
- ConnectionState5["CONNECTED"] = "CONNECTED";
28
- ConnectionState5["CLOSING"] = "CLOSING";
29
- ConnectionState5["CLOSED"] = "CLOSED";
30
- ConnectionState5["ABORTING"] = "ABORTING";
31
- ConnectionState5["ABORTED"] = "ABORTED";
32
- })(ConnectionState || (ConnectionState = {}));
33
- var Connection = class {
34
- constructor(topic, localInfo, remoteInfo, sessionId, initiator, _signalMessaging, _protocol, _transportFactory, _callbacks) {
35
- this.topic = topic;
36
- this.localInfo = localInfo;
37
- this.remoteInfo = remoteInfo;
38
- this.sessionId = sessionId;
39
- this.initiator = initiator;
40
- this._signalMessaging = _signalMessaging;
41
- this._protocol = _protocol;
42
- this._transportFactory = _transportFactory;
43
- this._callbacks = _callbacks;
44
- this._ctx = new Context(void 0, {
45
- F: __dxlog_file,
46
- L: 100
47
- });
48
- this.connectedTimeoutContext = new Context(void 0, {
49
- F: __dxlog_file,
50
- L: 101
51
- });
52
- this._protocolClosed = new Trigger();
53
- this._transportClosed = new Trigger();
54
- this._state = "CREATED";
55
- this._incomingSignalBuffer = [];
56
- this._outgoingSignalBuffer = [];
57
- this.stateChanged = new Event();
58
- this.errors = new ErrorStream();
59
- this._instanceId = PublicKey.random().toHex();
60
- this.transportStats = new Event();
61
- this._signalSendTask = new DeferredTask(this._ctx, async () => {
62
- await this._flushSignalBuffer();
63
- });
64
- this._signallingDelay = STARTING_SIGNALLING_DELAY;
65
- log.trace("dxos.mesh.connection.construct", {
66
- sessionId: this.sessionId,
67
- topic: this.topic,
68
- localPeer: this.localInfo,
69
- remotePeer: this.remoteInfo,
70
- initiator: this.initiator
71
- }, {
72
- F: __dxlog_file,
73
- L: 137,
74
- S: this,
75
- C: (f, a) => f(...a)
76
- });
77
- }
78
- get sessionIdString() {
79
- return this.sessionId.truncate();
80
- }
81
- get state() {
82
- return this._state;
83
- }
84
- get transport() {
85
- return this._transport;
86
- }
87
- get protocol() {
88
- return this._protocol;
89
- }
90
- /**
91
- * Create an underlying transport and prepares it for the connection.
92
- */
93
- async openConnection() {
94
- invariant(this._state === "INITIAL", "Invalid state.", {
95
- F: __dxlog_file,
96
- L: 167,
97
- S: this,
98
- A: [
99
- "this._state === ConnectionState.INITIAL",
100
- "'Invalid state.'"
101
- ]
102
- });
103
- log.trace("dxos.mesh.connection.open-connection", trace.begin({
104
- id: this._instanceId
105
- }), {
106
- F: __dxlog_file,
107
- L: 168,
108
- S: this,
109
- C: (f, a) => f(...a)
110
- });
111
- log.trace("dxos.mesh.connection.open", {
112
- sessionId: this.sessionId,
113
- topic: this.topic,
114
- localPeerId: this.localInfo,
115
- remotePeerId: this.remoteInfo,
116
- initiator: this.initiator
117
- }, {
118
- F: __dxlog_file,
119
- L: 169,
120
- S: this,
121
- C: (f, a) => f(...a)
122
- });
123
- this._changeState("CONNECTING");
124
- this._protocol.open(this.sessionId).catch((err) => {
125
- this.errors.raise(err);
126
- });
127
- this._protocol.stream.on("close", () => {
128
- log("protocol stream closed", void 0, {
129
- F: __dxlog_file,
130
- L: 186,
131
- S: this,
132
- C: (f, a) => f(...a)
133
- });
134
- this._protocolClosed.wake();
135
- this.close(new ProtocolError("protocol stream closed")).catch((err) => this.errors.raise(err));
136
- });
137
- scheduleTask(this.connectedTimeoutContext, async () => {
138
- log.info(`timeout waiting ${TRANSPORT_CONNECTION_TIMEOUT / 1e3}s for transport to connect, aborting`, void 0, {
139
- F: __dxlog_file,
140
- L: 194,
141
- S: this,
142
- C: (f, a) => f(...a)
143
- });
144
- await this.abort(new TimeoutError(`${TRANSPORT_CONNECTION_TIMEOUT / 1e3}s for transport to connect`)).catch((err) => this.errors.raise(err));
145
- }, TRANSPORT_CONNECTION_TIMEOUT);
146
- invariant(!this._transport, void 0, {
147
- F: __dxlog_file,
148
- L: 202,
149
- S: this,
150
- A: [
151
- "!this._transport",
152
- ""
153
- ]
154
- });
155
- this._transport = this._transportFactory.createTransport({
156
- ownPeerKey: this.localInfo.peerKey,
157
- remotePeerKey: this.remoteInfo.peerKey,
158
- topic: this.topic.toHex(),
159
- initiator: this.initiator,
160
- stream: this._protocol.stream,
161
- sendSignal: async (signal) => this._sendSignal(signal),
162
- sessionId: this.sessionId
163
- });
164
- this._transport.connected.once(async () => {
165
- this._changeState("CONNECTED");
166
- await this.connectedTimeoutContext.dispose();
167
- this._callbacks?.onConnected?.();
168
- scheduleTaskInterval(this._ctx, async () => this._emitTransportStats(), TRANSPORT_STATS_INTERVAL);
169
- });
170
- this._transport.closed.once(() => {
171
- this._transport = void 0;
172
- this._transportClosed.wake();
173
- log("abort triggered by transport close", void 0, {
174
- F: __dxlog_file,
175
- L: 224,
176
- S: this,
177
- C: (f, a) => f(...a)
178
- });
179
- this.abort().catch((err) => this.errors.raise(err));
180
- });
181
- this._transport.errors.handle(async (err) => {
182
- log("transport error:", {
183
- err
184
- }, {
185
- F: __dxlog_file,
186
- L: 229,
187
- S: this,
188
- C: (f, a) => f(...a)
189
- });
190
- if (!this.closeReason) {
191
- this.closeReason = err?.message;
192
- }
193
- if (err instanceof ConnectionResetError) {
194
- log.info("aborting due to transport ConnectionResetError", void 0, {
195
- F: __dxlog_file,
196
- L: 236,
197
- S: this,
198
- C: (f, a) => f(...a)
199
- });
200
- this.abort().catch((err2) => this.errors.raise(err2));
201
- } else if (err instanceof ConnectivityError) {
202
- log.info("aborting due to transport ConnectivityError", void 0, {
203
- F: __dxlog_file,
204
- L: 239,
205
- S: this,
206
- C: (f, a) => f(...a)
207
- });
208
- this.abort().catch((err2) => this.errors.raise(err2));
209
- }
210
- if (this._state !== "CLOSED" && this._state !== "CLOSING") {
211
- await this.connectedTimeoutContext.dispose();
212
- this.errors.raise(err);
213
- }
214
- });
215
- await this._transport.open();
216
- for (const signal of this._incomingSignalBuffer) {
217
- void this._transport.onSignal(signal);
218
- }
219
- this._incomingSignalBuffer = [];
220
- log.trace("dxos.mesh.connection.open-connection", trace.end({
221
- id: this._instanceId
222
- }), {
223
- F: __dxlog_file,
224
- L: 258,
225
- S: this,
226
- C: (f, a) => f(...a)
227
- });
228
- }
229
- async abort(err) {
230
- log("aborting...", {
231
- err
232
- }, {
233
- F: __dxlog_file,
234
- L: 265,
235
- S: this,
236
- C: (f, a) => f(...a)
237
- });
238
- if (this._state === "CLOSED" || this._state === "ABORTED") {
239
- log(`abort ignored: already ${this._state}`, this.closeReason, {
240
- F: __dxlog_file,
241
- L: 267,
242
- S: this,
243
- C: (f, a) => f(...a)
244
- });
245
- return;
246
- }
247
- await this.connectedTimeoutContext.dispose();
248
- this._changeState("ABORTING");
249
- if (!this.closeReason) {
250
- this.closeReason = err?.message;
251
- }
252
- await this._ctx.dispose();
253
- try {
254
- await this._closeProtocol({
255
- abort: true
256
- });
257
- } catch (err2) {
258
- log.catch(err2, void 0, {
259
- F: __dxlog_file,
260
- L: 283,
261
- S: this,
262
- C: (f, a) => f(...a)
263
- });
264
- }
265
- try {
266
- await this._closeTransport();
267
- } catch (err2) {
268
- log.catch(err2, void 0, {
269
- F: __dxlog_file,
270
- L: 290,
271
- S: this,
272
- C: (f, a) => f(...a)
273
- });
274
- }
275
- try {
276
- this._callbacks?.onClosed?.(err);
277
- } catch (err2) {
278
- log.catch(err2, void 0, {
279
- F: __dxlog_file,
280
- L: 296,
281
- S: this,
282
- C: (f, a) => f(...a)
283
- });
284
- }
285
- this._changeState("ABORTED");
286
- }
287
- async close(err) {
288
- if (!this.closeReason) {
289
- this.closeReason = err?.message;
290
- } else {
291
- this.closeReason += `; ${err?.message}`;
292
- }
293
- if (this._state === "CLOSED" || this._state === "ABORTING" || this._state === "ABORTED") {
294
- return;
295
- }
296
- const lastState = this._state;
297
- this._changeState("CLOSING");
298
- await this.connectedTimeoutContext.dispose();
299
- await this._ctx.dispose();
300
- log("closing...", {
301
- peerId: this.localInfo
302
- }, {
303
- F: __dxlog_file,
304
- L: 321,
305
- S: this,
306
- C: (f, a) => f(...a)
307
- });
308
- let abortProtocol = false;
309
- if (lastState !== "CONNECTED") {
310
- log(`graceful close requested when we were in ${lastState} state? aborting`, void 0, {
311
- F: __dxlog_file,
312
- L: 325,
313
- S: this,
314
- C: (f, a) => f(...a)
315
- });
316
- abortProtocol = true;
317
- }
318
- try {
319
- await this._closeProtocol({
320
- abort: abortProtocol
321
- });
322
- } catch (err2) {
323
- log.catch(err2, void 0, {
324
- F: __dxlog_file,
325
- L: 331,
326
- S: this,
327
- C: (f, a) => f(...a)
328
- });
329
- }
330
- try {
331
- await this._closeTransport();
332
- } catch (err2) {
333
- log.catch(err2, void 0, {
334
- F: __dxlog_file,
335
- L: 337,
336
- S: this,
337
- C: (f, a) => f(...a)
338
- });
339
- }
340
- log("closed", {
341
- peerId: this.localInfo
342
- }, {
343
- F: __dxlog_file,
344
- L: 340,
345
- S: this,
346
- C: (f, a) => f(...a)
347
- });
348
- this._changeState("CLOSED");
349
- this._callbacks?.onClosed?.(err);
350
- }
351
- async _closeProtocol(options) {
352
- log("closing protocol", options, {
353
- F: __dxlog_file,
354
- L: 346,
355
- S: this,
356
- C: (f, a) => f(...a)
357
- });
358
- await Promise.race([
359
- options?.abort ? this._protocol.abort() : this._protocol.close(),
360
- this._protocolClosed.wait()
361
- ]);
362
- log("protocol closed", options, {
363
- F: __dxlog_file,
364
- L: 348,
365
- S: this,
366
- C: (f, a) => f(...a)
367
- });
368
- }
369
- async _closeTransport() {
370
- log("closing transport", void 0, {
371
- F: __dxlog_file,
372
- L: 352,
373
- S: this,
374
- C: (f, a) => f(...a)
375
- });
376
- await Promise.race([
377
- this._transport?.close(),
378
- this._transportClosed.wait()
379
- ]);
380
- log("transport closed", void 0, {
381
- F: __dxlog_file,
382
- L: 354,
383
- S: this,
384
- C: (f, a) => f(...a)
385
- });
386
- }
387
- _sendSignal(signal) {
388
- this._outgoingSignalBuffer.push(signal);
389
- this._signalSendTask.schedule();
390
- }
391
- async _flushSignalBuffer() {
392
- if (this._outgoingSignalBuffer.length === 0) {
393
- return;
394
- }
395
- try {
396
- if (process.env.NODE_ENV !== "test") {
397
- await cancelWithContext(this._ctx, sleep(this._signallingDelay));
398
- this._signallingDelay = Math.min(this._signallingDelay * 2, MAX_SIGNALLING_DELAY);
399
- }
400
- const signals = [
401
- ...this._outgoingSignalBuffer
402
- ];
403
- this._outgoingSignalBuffer.length = 0;
404
- await this._signalMessaging.signal({
405
- author: this.localInfo,
406
- recipient: this.remoteInfo,
407
- sessionId: this.sessionId,
408
- topic: this.topic,
409
- data: {
410
- signalBatch: {
411
- signals
412
- }
413
- }
414
- });
415
- } catch (err) {
416
- if (err instanceof CancelledError || err instanceof ContextDisposedError || err instanceof Error && err.message?.includes("CANCELLED")) {
417
- return;
418
- }
419
- log.info("signal message failed to deliver", {
420
- err
421
- }, {
422
- F: __dxlog_file,
423
- L: 394,
424
- S: this,
425
- C: (f, a) => f(...a)
426
- });
427
- await this.close(new ConnectivityError("signal message failed to deliver", err));
428
- }
429
- }
430
- /**
431
- * Receive a signal from the remote peer.
432
- */
433
- async signal(msg) {
434
- invariant(msg.sessionId, void 0, {
435
- F: __dxlog_file,
436
- L: 403,
437
- S: this,
438
- A: [
439
- "msg.sessionId",
440
- ""
441
- ]
442
- });
443
- if (!msg.sessionId.equals(this.sessionId)) {
444
- log("dropping signal for incorrect session id", void 0, {
445
- F: __dxlog_file,
446
- L: 405,
447
- S: this,
448
- C: (f, a) => f(...a)
449
- });
450
- return;
451
- }
452
- invariant(msg.data.signal || msg.data.signalBatch, void 0, {
453
- F: __dxlog_file,
454
- L: 408,
455
- S: this,
456
- A: [
457
- "msg.data.signal || msg.data.signalBatch",
458
- ""
459
- ]
460
- });
461
- invariant(msg.author.peerKey === this.remoteInfo.peerKey, void 0, {
462
- F: __dxlog_file,
463
- L: 409,
464
- S: this,
465
- A: [
466
- "msg.author.peerKey === this.remoteInfo.peerKey",
467
- ""
468
- ]
469
- });
470
- invariant(msg.recipient.peerKey === this.localInfo.peerKey, void 0, {
471
- F: __dxlog_file,
472
- L: 410,
473
- S: this,
474
- A: [
475
- "msg.recipient.peerKey === this.localInfo.peerKey",
476
- ""
477
- ]
478
- });
479
- const signals = msg.data.signalBatch ? msg.data.signalBatch.signals ?? [] : [
480
- msg.data.signal
481
- ];
482
- for (const signal of signals) {
483
- if (!signal) {
484
- continue;
485
- }
486
- if ([
487
- "CREATED",
488
- "INITIAL"
489
- ].includes(this.state)) {
490
- log("buffered signal", {
491
- peerId: this.localInfo,
492
- remoteId: this.remoteInfo,
493
- msg: msg.data
494
- }, {
495
- F: __dxlog_file,
496
- L: 419,
497
- S: this,
498
- C: (f, a) => f(...a)
499
- });
500
- this._incomingSignalBuffer.push(signal);
501
- } else {
502
- invariant(this._transport, "Connection not ready to accept signals.", {
503
- F: __dxlog_file,
504
- L: 422,
505
- S: this,
506
- A: [
507
- "this._transport",
508
- "'Connection not ready to accept signals.'"
509
- ]
510
- });
511
- log("received signal", {
512
- peerId: this.localInfo,
513
- remoteId: this.remoteInfo,
514
- msg: msg.data
515
- }, {
516
- F: __dxlog_file,
517
- L: 423,
518
- S: this,
519
- C: (f, a) => f(...a)
520
- });
521
- await this._transport.onSignal(signal);
522
- }
523
- }
524
- }
525
- initiate() {
526
- this._changeState("INITIAL");
527
- }
528
- _changeState(state) {
529
- log("stateChanged", {
530
- from: this._state,
531
- to: state,
532
- peerId: this.localInfo
533
- }, {
534
- F: __dxlog_file,
535
- L: 434,
536
- S: this,
537
- C: (f, a) => f(...a)
538
- });
539
- invariant(state !== this._state, "Already in this state.", {
540
- F: __dxlog_file,
541
- L: 435,
542
- S: this,
543
- A: [
544
- "state !== this._state",
545
- "'Already in this state.'"
546
- ]
547
- });
548
- this._state = state;
549
- this.stateChanged.emit(state);
550
- }
551
- async _emitTransportStats() {
552
- const stats = await this.transport?.getStats();
553
- if (stats) {
554
- this.transportStats.emit(stats);
555
- }
556
- }
557
- };
558
- _ts_decorate([
559
- logInfo
560
- ], Connection.prototype, "sessionIdString", null);
561
- _ts_decorate([
562
- synchronized
563
- ], Connection.prototype, "abort", null);
564
- _ts_decorate([
565
- synchronized
566
- ], Connection.prototype, "close", null);
567
-
568
- // packages/core/mesh/network-manager/src/signal/ice.ts
569
- import { asyncTimeout } from "@dxos/async";
570
- import { log as log2 } from "@dxos/log";
571
- import { isNotNullOrUndefined } from "@dxos/util";
572
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/signal/ice.ts";
573
- var createIceProvider = (iceProviders) => {
574
- let cachedIceServers;
575
- return {
576
- getIceServers: async () => {
577
- if (cachedIceServers) {
578
- return cachedIceServers;
579
- }
580
- cachedIceServers = (await Promise.all(iceProviders.map(({ urls }) => asyncTimeout(fetch(urls, {
581
- method: "GET"
582
- }), 1e4).then((response) => response.json()).catch((err) => log2.error("Failed to fetch ICE servers from provider", {
583
- urls,
584
- err
585
- }, {
586
- F: __dxlog_file2,
587
- L: 27,
588
- S: void 0,
589
- C: (f, a) => f(...a)
590
- }))))).filter(isNotNullOrUndefined).map(({ iceServers }) => iceServers).flat();
591
- return cachedIceServers;
592
- }
593
- };
594
- };
595
-
596
- // packages/core/mesh/network-manager/src/signal/swarm-messenger.ts
597
- import { Context as Context2 } from "@dxos/context";
598
- import { invariant as invariant2 } from "@dxos/invariant";
599
- import { PublicKey as PublicKey2 } from "@dxos/keys";
600
- import { log as log3 } from "@dxos/log";
601
- import { TimeoutError as TimeoutError2 } from "@dxos/protocols";
602
- import { schema } from "@dxos/protocols/proto";
603
- import { ComplexMap } from "@dxos/util";
604
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/signal/swarm-messenger.ts";
605
- var SwarmMessage = schema.getCodecForType("dxos.mesh.swarm.SwarmMessage");
606
- var SwarmMessenger = class {
607
- constructor({ sendMessage, onSignal, onOffer, topic }) {
608
- this._ctx = new Context2(void 0, {
609
- F: __dxlog_file3,
610
- L: 35
611
- });
612
- this._offerRecords = new ComplexMap((key) => key.toHex());
613
- this._sendMessage = sendMessage;
614
- this._onSignal = onSignal;
615
- this._onOffer = onOffer;
616
- this._topic = topic;
617
- }
618
- async receiveMessage({ author, recipient, payload }) {
619
- if (payload.type_url !== "dxos.mesh.swarm.SwarmMessage") {
620
- return;
621
- }
622
- const message = SwarmMessage.decode(payload.value);
623
- if (!this._topic.equals(message.topic)) {
624
- return;
625
- }
626
- log3("received", {
627
- from: author,
628
- to: recipient,
629
- msg: message
630
- }, {
631
- F: __dxlog_file3,
632
- L: 71,
633
- S: this,
634
- C: (f, a) => f(...a)
635
- });
636
- if (message.data?.offer) {
637
- await this._handleOffer({
638
- author,
639
- recipient,
640
- message
641
- });
642
- } else if (message.data?.answer) {
643
- await this._resolveAnswers(message);
644
- } else if (message.data?.signal) {
645
- await this._handleSignal({
646
- author,
647
- recipient,
648
- message
649
- });
650
- } else if (message.data?.signalBatch) {
651
- await this._handleSignal({
652
- author,
653
- recipient,
654
- message
655
- });
656
- } else {
657
- log3.warn("unknown message", {
658
- message
659
- }, {
660
- F: __dxlog_file3,
661
- L: 82,
662
- S: this,
663
- C: (f, a) => f(...a)
664
- });
665
- }
666
- }
667
- async signal(message) {
668
- invariant2(message.data?.signal || message.data?.signalBatch, "Invalid message", {
669
- F: __dxlog_file3,
670
- L: 87,
671
- S: this,
672
- A: [
673
- "message.data?.signal || message.data?.signalBatch",
674
- "'Invalid message'"
675
- ]
676
- });
677
- await this._sendReliableMessage({
678
- author: message.author,
679
- recipient: message.recipient,
680
- message
681
- });
682
- }
683
- async offer(message) {
684
- const networkMessage = {
685
- ...message,
686
- messageId: PublicKey2.random()
687
- };
688
- return new Promise((resolve, reject) => {
689
- this._offerRecords.set(networkMessage.messageId, {
690
- resolve
691
- });
692
- this._sendReliableMessage({
693
- author: message.author,
694
- recipient: message.recipient,
695
- message: networkMessage
696
- }).catch((err) => reject(err));
697
- });
698
- }
699
- async _sendReliableMessage({ author, recipient, message }) {
700
- const networkMessage = {
701
- ...message,
702
- // Setting unique message_id if it not specified yet.
703
- messageId: message.messageId ?? PublicKey2.random()
704
- };
705
- log3("sending", {
706
- from: author,
707
- to: recipient,
708
- msg: networkMessage
709
- }, {
710
- F: __dxlog_file3,
711
- L: 125,
712
- S: this,
713
- C: (f, a) => f(...a)
714
- });
715
- await this._sendMessage({
716
- author,
717
- recipient,
718
- payload: {
719
- type_url: "dxos.mesh.swarm.SwarmMessage",
720
- value: SwarmMessage.encode(networkMessage)
721
- }
722
- });
723
- }
724
- async _resolveAnswers(message) {
725
- invariant2(message.data?.answer?.offerMessageId, "No offerMessageId", {
726
- F: __dxlog_file3,
727
- L: 137,
728
- S: this,
729
- A: [
730
- "message.data?.answer?.offerMessageId",
731
- "'No offerMessageId'"
732
- ]
733
- });
734
- const offerRecord = this._offerRecords.get(message.data.answer.offerMessageId);
735
- if (offerRecord) {
736
- this._offerRecords.delete(message.data.answer.offerMessageId);
737
- invariant2(message.data?.answer, "No answer", {
738
- F: __dxlog_file3,
739
- L: 141,
740
- S: this,
741
- A: [
742
- "message.data?.answer",
743
- "'No answer'"
744
- ]
745
- });
746
- log3("resolving", {
747
- answer: message.data.answer
748
- }, {
749
- F: __dxlog_file3,
750
- L: 142,
751
- S: this,
752
- C: (f, a) => f(...a)
753
- });
754
- offerRecord.resolve(message.data.answer);
755
- }
756
- }
757
- async _handleOffer({ author, recipient, message }) {
758
- invariant2(message.data.offer, "No offer", {
759
- F: __dxlog_file3,
760
- L: 156,
761
- S: this,
762
- A: [
763
- "message.data.offer",
764
- "'No offer'"
765
- ]
766
- });
767
- const offerMessage = {
768
- author,
769
- recipient,
770
- ...message,
771
- data: {
772
- offer: message.data.offer
773
- }
774
- };
775
- const answer = await this._onOffer(offerMessage);
776
- answer.offerMessageId = message.messageId;
777
- try {
778
- await this._sendReliableMessage({
779
- author: recipient,
780
- recipient: author,
781
- message: {
782
- topic: message.topic,
783
- sessionId: message.sessionId,
784
- data: {
785
- answer
786
- }
787
- }
788
- });
789
- } catch (err) {
790
- if (err instanceof TimeoutError2) {
791
- log3.info("timeout sending answer to offer", {
792
- err
793
- }, {
794
- F: __dxlog_file3,
795
- L: 177,
796
- S: this,
797
- C: (f, a) => f(...a)
798
- });
799
- } else {
800
- log3.info("error sending answer to offer", {
801
- err
802
- }, {
803
- F: __dxlog_file3,
804
- L: 179,
805
- S: this,
806
- C: (f, a) => f(...a)
807
- });
808
- }
809
- }
810
- }
811
- async _handleSignal({ author, recipient, message }) {
812
- invariant2(message.messageId, void 0, {
813
- F: __dxlog_file3,
814
- L: 193,
815
- S: this,
816
- A: [
817
- "message.messageId",
818
- ""
819
- ]
820
- });
821
- invariant2(message.data.signal || message.data.signalBatch, "Invalid message", {
822
- F: __dxlog_file3,
823
- L: 194,
824
- S: this,
825
- A: [
826
- "message.data.signal || message.data.signalBatch",
827
- "'Invalid message'"
828
- ]
829
- });
830
- const signalMessage = {
831
- author,
832
- recipient,
833
- ...message,
834
- data: {
835
- signal: message.data.signal,
836
- signalBatch: message.data.signalBatch
837
- }
838
- };
839
- await this._onSignal(signalMessage);
840
- }
841
- };
842
-
843
- // packages/core/mesh/network-manager/src/swarm/swarm.ts
844
- import { Event as Event3, scheduleTask as scheduleTask3, sleep as sleep2, synchronized as synchronized3 } from "@dxos/async";
845
- import { Context as Context4 } from "@dxos/context";
846
- import { ErrorStream as ErrorStream2 } from "@dxos/debug";
847
- import { invariant as invariant4 } from "@dxos/invariant";
848
- import { PublicKey as PublicKey4 } from "@dxos/keys";
849
- import { log as log5, logInfo as logInfo2 } from "@dxos/log";
850
- import { PeerInfoHash } from "@dxos/messaging";
851
- import { trace as trace2 } from "@dxos/protocols";
852
- import { ComplexMap as ComplexMap2, isNotNullOrUndefined as isNotNullOrUndefined2 } from "@dxos/util";
853
-
854
- // packages/core/mesh/network-manager/src/swarm/peer.ts
855
- import { Event as Event2, scheduleTask as scheduleTask2, synchronized as synchronized2 } from "@dxos/async";
856
- import { Context as Context3 } from "@dxos/context";
857
- import { invariant as invariant3 } from "@dxos/invariant";
858
- import { PublicKey as PublicKey3 } from "@dxos/keys";
859
- import { log as log4 } from "@dxos/log";
860
- import { CancelledError as CancelledError2, SystemError } from "@dxos/protocols";
861
- function _ts_decorate2(decorators, target, key, desc) {
862
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
863
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
864
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
865
- return c > 3 && r && Object.defineProperty(target, key, r), r;
866
- }
867
- var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/swarm/peer.ts";
868
- var ConnectionDisplacedError = class extends SystemError {
869
- constructor() {
870
- super("Connection displaced by remote initiator.");
871
- }
872
- };
873
- var CONNECTION_COUNTS_STABLE_AFTER = 5e3;
874
- var Peer = class {
875
- constructor(remoteInfo, topic, localInfo, _signalMessaging, _protocolProvider, _transportFactory, _connectionLimiter, _callbacks) {
876
- this.remoteInfo = remoteInfo;
877
- this.topic = topic;
878
- this.localInfo = localInfo;
879
- this._signalMessaging = _signalMessaging;
880
- this._protocolProvider = _protocolProvider;
881
- this._transportFactory = _transportFactory;
882
- this._connectionLimiter = _connectionLimiter;
883
- this._callbacks = _callbacks;
884
- this._availableAfter = 0;
885
- this.availableToConnect = true;
886
- this._ctx = new Context3(void 0, {
887
- F: __dxlog_file4,
888
- L: 80
889
- });
890
- this.advertizing = false;
891
- this.initiating = false;
892
- this.connectionDisplaced = new Event2();
893
- }
894
- /**
895
- * Respond to remote offer.
896
- */
897
- async onOffer(message) {
898
- const remote = message.author;
899
- if (this.connection && ![
900
- ConnectionState.CREATED,
901
- ConnectionState.INITIAL,
902
- ConnectionState.CONNECTING
903
- ].includes(this.connection.state)) {
904
- log4.info(`received offer when connection already in ${this.connection.state} state`, void 0, {
905
- F: __dxlog_file4,
906
- L: 115,
907
- S: this,
908
- C: (f, a) => f(...a)
909
- });
910
- return {
911
- accept: false
912
- };
913
- }
914
- if (this.connection || this.initiating) {
915
- if (remote.peerKey < this.localInfo.peerKey) {
916
- log4("close local connection", {
917
- localPeer: this.localInfo,
918
- topic: this.topic,
919
- remotePeer: this.remoteInfo,
920
- sessionId: this.connection?.sessionId
921
- }, {
922
- F: __dxlog_file4,
923
- L: 124,
924
- S: this,
925
- C: (f, a) => f(...a)
926
- });
927
- if (this.connection) {
928
- await this.closeConnection(new ConnectionDisplacedError());
929
- }
930
- } else {
931
- return {
932
- accept: false
933
- };
934
- }
935
- }
936
- if (await this._callbacks.onOffer(remote)) {
937
- if (!this.connection) {
938
- invariant3(message.sessionId, void 0, {
939
- F: __dxlog_file4,
940
- L: 144,
941
- S: this,
942
- A: [
943
- "message.sessionId",
944
- ""
945
- ]
946
- });
947
- const connection = this._createConnection(false, message.sessionId);
948
- try {
949
- await this._connectionLimiter.connecting(message.sessionId);
950
- connection.initiate();
951
- await connection.openConnection();
952
- } catch (err) {
953
- if (!(err instanceof CancelledError2)) {
954
- log4.info("connection error", {
955
- topic: this.topic,
956
- peerId: this.localInfo,
957
- remoteId: this.remoteInfo,
958
- err
959
- }, {
960
- F: __dxlog_file4,
961
- L: 154,
962
- S: this,
963
- C: (f, a) => f(...a)
964
- });
965
- }
966
- await this.closeConnection(err);
967
- }
968
- return {
969
- accept: true
970
- };
971
- }
972
- }
973
- return {
974
- accept: false
975
- };
976
- }
977
- /**
978
- * Initiate a connection to the remote peer.
979
- */
980
- async initiateConnection() {
981
- invariant3(!this.initiating, "Initiation in progress.", {
982
- F: __dxlog_file4,
983
- L: 171,
984
- S: this,
985
- A: [
986
- "!this.initiating",
987
- "'Initiation in progress.'"
988
- ]
989
- });
990
- invariant3(!this.connection, "Already connected.", {
991
- F: __dxlog_file4,
992
- L: 172,
993
- S: this,
994
- A: [
995
- "!this.connection",
996
- "'Already connected.'"
997
- ]
998
- });
999
- const sessionId = PublicKey3.random();
1000
- log4("initiating...", {
1001
- local: this.localInfo,
1002
- topic: this.topic,
1003
- remote: this.remoteInfo,
1004
- sessionId
1005
- }, {
1006
- F: __dxlog_file4,
1007
- L: 174,
1008
- S: this,
1009
- C: (f, a) => f(...a)
1010
- });
1011
- const connection = this._createConnection(true, sessionId);
1012
- this.initiating = true;
1013
- let answer;
1014
- try {
1015
- await this._connectionLimiter.connecting(sessionId);
1016
- connection.initiate();
1017
- answer = await this._signalMessaging.offer({
1018
- author: this.localInfo,
1019
- recipient: this.remoteInfo,
1020
- sessionId,
1021
- topic: this.topic,
1022
- data: {
1023
- offer: {}
1024
- }
1025
- });
1026
- log4("received", {
1027
- answer,
1028
- topic: this.topic,
1029
- local: this.localInfo,
1030
- remote: this.remoteInfo
1031
- }, {
1032
- F: __dxlog_file4,
1033
- L: 191,
1034
- S: this,
1035
- C: (f, a) => f(...a)
1036
- });
1037
- if (connection.state !== ConnectionState.INITIAL) {
1038
- log4("ignoring response", void 0, {
1039
- F: __dxlog_file4,
1040
- L: 193,
1041
- S: this,
1042
- C: (f, a) => f(...a)
1043
- });
1044
- return;
1045
- }
1046
- } catch (err) {
1047
- log4("initiation error: send offer", {
1048
- err,
1049
- topic: this.topic,
1050
- local: this.localInfo,
1051
- remote: this.remoteInfo
1052
- }, {
1053
- F: __dxlog_file4,
1054
- L: 197,
1055
- S: this,
1056
- C: (f, a) => f(...a)
1057
- });
1058
- await connection.abort(err);
1059
- throw err;
1060
- } finally {
1061
- this.initiating = false;
1062
- }
1063
- try {
1064
- if (!answer.accept) {
1065
- this._callbacks.onRejected();
1066
- return;
1067
- }
1068
- } catch (err) {
1069
- log4("initiation error: accept answer", {
1070
- err,
1071
- topic: this.topic,
1072
- local: this.localInfo,
1073
- remote: this.remoteInfo
1074
- }, {
1075
- F: __dxlog_file4,
1076
- L: 210,
1077
- S: this,
1078
- C: (f, a) => f(...a)
1079
- });
1080
- await connection.abort(err);
1081
- throw err;
1082
- } finally {
1083
- this.initiating = false;
1084
- }
1085
- try {
1086
- log4("opening connection as initiator", void 0, {
1087
- F: __dxlog_file4,
1088
- L: 223,
1089
- S: this,
1090
- C: (f, a) => f(...a)
1091
- });
1092
- await connection.openConnection();
1093
- this._callbacks.onAccepted();
1094
- } catch (err) {
1095
- log4("initiation error: open connection", {
1096
- err,
1097
- topic: this.topic,
1098
- local: this.localInfo,
1099
- remote: this.remoteInfo
1100
- }, {
1101
- F: __dxlog_file4,
1102
- L: 227,
1103
- S: this,
1104
- C: (f, a) => f(...a)
1105
- });
1106
- log4.warn("closing connection due to unhandled error on openConnection", {
1107
- err
1108
- }, {
1109
- F: __dxlog_file4,
1110
- L: 234,
1111
- S: this,
1112
- C: (f, a) => f(...a)
1113
- });
1114
- await this.closeConnection(err);
1115
- throw err;
1116
- } finally {
1117
- this.initiating = false;
1118
- }
1119
- }
1120
- /**
1121
- * Create new connection.
1122
- * Either we're initiating a connection or creating one in response to an offer from the other peer.
1123
- */
1124
- _createConnection(initiator, sessionId) {
1125
- log4("creating connection", {
1126
- topic: this.topic,
1127
- peerId: this.localInfo,
1128
- remoteId: this.remoteInfo,
1129
- initiator,
1130
- sessionId
1131
- }, {
1132
- F: __dxlog_file4,
1133
- L: 248,
1134
- S: this,
1135
- C: (f, a) => f(...a)
1136
- });
1137
- invariant3(!this.connection, "Already connected.", {
1138
- F: __dxlog_file4,
1139
- L: 255,
1140
- S: this,
1141
- A: [
1142
- "!this.connection",
1143
- "'Already connected.'"
1144
- ]
1145
- });
1146
- const connection = new Connection(
1147
- this.topic,
1148
- this.localInfo,
1149
- this.remoteInfo,
1150
- sessionId,
1151
- initiator,
1152
- this._signalMessaging,
1153
- // TODO(dmaretskyi): Init only when connection is established.
1154
- this._protocolProvider({
1155
- initiator,
1156
- localPeerId: PublicKey3.from(this.localInfo.peerKey),
1157
- remotePeerId: PublicKey3.from(this.remoteInfo.peerKey),
1158
- topic: this.topic
1159
- }),
1160
- this._transportFactory,
1161
- {
1162
- onConnected: () => {
1163
- this.availableToConnect = true;
1164
- this._lastConnectionTime = Date.now();
1165
- this._callbacks.onConnected();
1166
- this._connectionLimiter.doneConnecting(sessionId);
1167
- log4.trace("dxos.mesh.connection.connected", {
1168
- topic: this.topic,
1169
- localPeerId: this.localInfo,
1170
- remotePeerId: this.remoteInfo,
1171
- sessionId,
1172
- initiator
1173
- }, {
1174
- F: __dxlog_file4,
1175
- L: 279,
1176
- S: this,
1177
- C: (f, a) => f(...a)
1178
- });
1179
- },
1180
- onClosed: (err) => {
1181
- log4("connection closed", {
1182
- topic: this.topic,
1183
- peerId: this.localInfo,
1184
- remoteId: this.remoteInfo,
1185
- initiator
1186
- }, {
1187
- F: __dxlog_file4,
1188
- L: 288,
1189
- S: this,
1190
- C: (f, a) => f(...a)
1191
- });
1192
- this._connectionLimiter.doneConnecting(sessionId);
1193
- invariant3(this.connection === connection, "Connection mismatch (race condition).", {
1194
- F: __dxlog_file4,
1195
- L: 293,
1196
- S: this,
1197
- A: [
1198
- "this.connection === connection",
1199
- "'Connection mismatch (race condition).'"
1200
- ]
1201
- });
1202
- log4.trace("dxos.mesh.connection.closed", {
1203
- topic: this.topic,
1204
- localPeerId: this.localInfo,
1205
- remotePeerId: this.remoteInfo,
1206
- sessionId,
1207
- initiator
1208
- }, {
1209
- F: __dxlog_file4,
1210
- L: 295,
1211
- S: this,
1212
- C: (f, a) => f(...a)
1213
- });
1214
- if (err instanceof ConnectionDisplacedError) {
1215
- this.connectionDisplaced.emit(this.connection);
1216
- } else {
1217
- if (this._lastConnectionTime && this._lastConnectionTime + CONNECTION_COUNTS_STABLE_AFTER < Date.now()) {
1218
- this._availableAfter = 0;
1219
- } else {
1220
- this.availableToConnect = false;
1221
- this._availableAfter = increaseInterval(this._availableAfter);
1222
- }
1223
- this._callbacks.onDisconnected();
1224
- scheduleTask2(this._connectionCtx, () => {
1225
- this.availableToConnect = true;
1226
- this._callbacks.onPeerAvailable();
1227
- }, this._availableAfter);
1228
- }
1229
- this.connection = void 0;
1230
- }
1231
- }
1232
- );
1233
- this._callbacks.onInitiated(connection);
1234
- void this._connectionCtx?.dispose();
1235
- this._connectionCtx = this._ctx.derive();
1236
- connection.errors.handle((err) => {
1237
- log4.info("connection error, closing", {
1238
- topic: this.topic,
1239
- peerId: this.localInfo,
1240
- remoteId: this.remoteInfo,
1241
- initiator,
1242
- err
1243
- }, {
1244
- F: __dxlog_file4,
1245
- L: 335,
1246
- S: this,
1247
- C: (f, a) => f(...a)
1248
- });
1249
- log4.trace("dxos.mesh.connection.error", {
1250
- topic: this.topic,
1251
- localPeerId: this.localInfo,
1252
- remotePeerId: this.remoteInfo,
1253
- sessionId,
1254
- initiator,
1255
- err
1256
- }, {
1257
- F: __dxlog_file4,
1258
- L: 342,
1259
- S: this,
1260
- C: (f, a) => f(...a)
1261
- });
1262
- void this.closeConnection(err);
1263
- });
1264
- this.connection = connection;
1265
- return connection;
1266
- }
1267
- async closeConnection(err) {
1268
- if (!this.connection) {
1269
- return;
1270
- }
1271
- const connection = this.connection;
1272
- log4("closing...", {
1273
- peerId: this.remoteInfo,
1274
- sessionId: connection.sessionId
1275
- }, {
1276
- F: __dxlog_file4,
1277
- L: 367,
1278
- S: this,
1279
- C: (f, a) => f(...a)
1280
- });
1281
- await connection.close(err);
1282
- log4("closed", {
1283
- peerId: this.remoteInfo,
1284
- sessionId: connection.sessionId
1285
- }, {
1286
- F: __dxlog_file4,
1287
- L: 373,
1288
- S: this,
1289
- C: (f, a) => f(...a)
1290
- });
1291
- }
1292
- async onSignal(message) {
1293
- if (!this.connection) {
1294
- log4("dropping signal message for non-existent connection", {
1295
- message
1296
- }, {
1297
- F: __dxlog_file4,
1298
- L: 378,
1299
- S: this,
1300
- C: (f, a) => f(...a)
1301
- });
1302
- return;
1303
- }
1304
- await this.connection.signal(message);
1305
- }
1306
- async safeDestroy(reason) {
1307
- await this._ctx.dispose();
1308
- log4("Destroying peer", {
1309
- peerId: this.remoteInfo,
1310
- topic: this.topic
1311
- }, {
1312
- F: __dxlog_file4,
1313
- L: 388,
1314
- S: this,
1315
- C: (f, a) => f(...a)
1316
- });
1317
- await this?.connection?.close(reason);
1318
- }
1319
- };
1320
- _ts_decorate2([
1321
- synchronized2
1322
- ], Peer.prototype, "safeDestroy", null);
1323
- var increaseInterval = (interval) => {
1324
- if (interval === 0) {
1325
- return 50;
1326
- } else if (interval < 500) {
1327
- return 500;
1328
- } else if (interval < 1e3) {
1329
- return 1e3;
1330
- } else if (interval < 5e3) {
1331
- return 5e3;
1332
- }
1333
- return 1e4;
1334
- };
1335
-
1336
- // packages/core/mesh/network-manager/src/swarm/swarm.ts
1337
- function _ts_decorate3(decorators, target, key, desc) {
1338
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1339
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1340
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1341
- return c > 3 && r && Object.defineProperty(target, key, r), r;
1342
- }
1343
- var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/swarm/swarm.ts";
1344
- var INITIATION_DELAY = 100;
1345
- var getClassName = (obj) => Object.getPrototypeOf(obj).constructor.name;
1346
- var Swarm = class {
1347
- // TODO(burdon): Swarm => Peer.create/destroy =< Connection.open/close
1348
- // TODO(burdon): Pass in object.
1349
- constructor(_topic, _ownPeer, _topology, _protocolProvider, _messenger, _transportFactory, _label, _connectionLimiter, _initiationDelay = INITIATION_DELAY) {
1350
- this._topic = _topic;
1351
- this._ownPeer = _ownPeer;
1352
- this._topology = _topology;
1353
- this._protocolProvider = _protocolProvider;
1354
- this._messenger = _messenger;
1355
- this._transportFactory = _transportFactory;
1356
- this._label = _label;
1357
- this._connectionLimiter = _connectionLimiter;
1358
- this._initiationDelay = _initiationDelay;
1359
- this._ctx = new Context4(void 0, {
1360
- F: __dxlog_file5,
1361
- L: 38
1362
- });
1363
- this._listeningHandle = void 0;
1364
- this._peers = new ComplexMap2(PeerInfoHash);
1365
- this._instanceId = PublicKey4.random().toHex();
1366
- this.connectionAdded = new Event3();
1367
- this.disconnected = new Event3();
1368
- this.connected = new Event3();
1369
- this.errors = new ErrorStream2();
1370
- log5.trace("dxos.mesh.swarm.constructor", trace2.begin({
1371
- id: this._instanceId,
1372
- data: {
1373
- topic: this._topic.toHex(),
1374
- peer: this._ownPeer
1375
- }
1376
- }), {
1377
- F: __dxlog_file5,
1378
- L: 88,
1379
- S: this,
1380
- C: (f, a) => f(...a)
1381
- });
1382
- log5("creating swarm", {
1383
- peerId: _ownPeer
1384
- }, {
1385
- F: __dxlog_file5,
1386
- L: 92,
1387
- S: this,
1388
- C: (f, a) => f(...a)
1389
- });
1390
- _topology.init(this._getSwarmController());
1391
- this._swarmMessenger = new SwarmMessenger({
1392
- sendMessage: async (msg) => await this._messenger.sendMessage(msg),
1393
- onSignal: async (msg) => await this.onSignal(msg),
1394
- onOffer: async (msg) => await this.onOffer(msg),
1395
- topic: this._topic
1396
- });
1397
- log5.trace("dxos.mesh.swarm.constructor", trace2.end({
1398
- id: this._instanceId
1399
- }), {
1400
- F: __dxlog_file5,
1401
- L: 101,
1402
- S: this,
1403
- C: (f, a) => f(...a)
1404
- });
1405
- }
1406
- get connections() {
1407
- return Array.from(this._peers.values()).map((peer) => peer.connection).filter(isNotNullOrUndefined2);
1408
- }
1409
- get ownPeerId() {
1410
- return PublicKey4.from(this._ownPeer.peerKey);
1411
- }
1412
- get ownPeer() {
1413
- return this._ownPeer;
1414
- }
1415
- /**
1416
- * Custom label assigned to this swarm. Used in devtools to display human-readable names for swarms.
1417
- */
1418
- get label() {
1419
- return this._label;
1420
- }
1421
- get topic() {
1422
- return this._topic;
1423
- }
1424
- async open() {
1425
- invariant4(!this._listeningHandle, void 0, {
1426
- F: __dxlog_file5,
1427
- L: 132,
1428
- S: this,
1429
- A: [
1430
- "!this._listeningHandle",
1431
- ""
1432
- ]
1433
- });
1434
- this._listeningHandle = await this._messenger.listen({
1435
- peer: this._ownPeer,
1436
- payloadType: "dxos.mesh.swarm.SwarmMessage",
1437
- onMessage: async (message) => {
1438
- await this._swarmMessenger.receiveMessage(message).catch((err) => log5.info("Error while receiving message", {
1439
- err
1440
- }, {
1441
- F: __dxlog_file5,
1442
- L: 140,
1443
- S: this,
1444
- C: (f, a) => f(...a)
1445
- }));
1446
- }
1447
- });
1448
- }
1449
- async destroy() {
1450
- log5("destroying...", void 0, {
1451
- F: __dxlog_file5,
1452
- L: 146,
1453
- S: this,
1454
- C: (f, a) => f(...a)
1455
- });
1456
- await this._listeningHandle?.unsubscribe();
1457
- this._listeningHandle = void 0;
1458
- await this._ctx.dispose();
1459
- await this._topology.destroy();
1460
- await Promise.all(Array.from(this._peers.keys()).map((key) => this._destroyPeer(key, "swarm destroyed")));
1461
- log5("destroyed", void 0, {
1462
- F: __dxlog_file5,
1463
- L: 153,
1464
- S: this,
1465
- C: (f, a) => f(...a)
1466
- });
1467
- }
1468
- async setTopology(topology) {
1469
- invariant4(!this._ctx.disposed, "Swarm is offline", {
1470
- F: __dxlog_file5,
1471
- L: 157,
1472
- S: this,
1473
- A: [
1474
- "!this._ctx.disposed",
1475
- "'Swarm is offline'"
1476
- ]
1477
- });
1478
- if (topology === this._topology) {
1479
- return;
1480
- }
1481
- log5("setting topology", {
1482
- previous: getClassName(this._topology),
1483
- topology: getClassName(topology)
1484
- }, {
1485
- F: __dxlog_file5,
1486
- L: 161,
1487
- S: this,
1488
- C: (f, a) => f(...a)
1489
- });
1490
- await this._topology.destroy();
1491
- this._topology = topology;
1492
- this._topology.init(this._getSwarmController());
1493
- this._topology.update();
1494
- }
1495
- onSwarmEvent(swarmEvent) {
1496
- log5("swarm event", {
1497
- swarmEvent
1498
- }, {
1499
- F: __dxlog_file5,
1500
- L: 174,
1501
- S: this,
1502
- C: (f, a) => f(...a)
1503
- });
1504
- if (this._ctx.disposed) {
1505
- log5("swarm event ignored for disposed swarm", void 0, {
1506
- F: __dxlog_file5,
1507
- L: 177,
1508
- S: this,
1509
- C: (f, a) => f(...a)
1510
- });
1511
- return;
1512
- }
1513
- if (swarmEvent.peerAvailable) {
1514
- const peerId = swarmEvent.peerAvailable.peer.peerKey;
1515
- if (peerId !== this._ownPeer.peerKey) {
1516
- log5("new peer", {
1517
- peerId
1518
- }, {
1519
- F: __dxlog_file5,
1520
- L: 184,
1521
- S: this,
1522
- C: (f, a) => f(...a)
1523
- });
1524
- const peer = this._getOrCreatePeer(swarmEvent.peerAvailable.peer);
1525
- peer.advertizing = true;
1526
- }
1527
- } else if (swarmEvent.peerLeft) {
1528
- const peer = this._peers.get(swarmEvent.peerLeft.peer);
1529
- if (peer) {
1530
- peer.advertizing = false;
1531
- if (peer.connection?.state !== ConnectionState.CONNECTED) {
1532
- void this._destroyPeer(swarmEvent.peerLeft.peer, "peer left").catch((err) => log5.catch(err, void 0, {
1533
- F: __dxlog_file5,
1534
- L: 194,
1535
- S: this,
1536
- C: (f, a) => f(...a)
1537
- }));
1538
- }
1539
- } else {
1540
- log5("received peerLeft but no peer found", {
1541
- peer: swarmEvent.peerLeft.peer.peerKey
1542
- }, {
1543
- F: __dxlog_file5,
1544
- L: 197,
1545
- S: this,
1546
- C: (f, a) => f(...a)
1547
- });
1548
- }
1549
- }
1550
- this._topology.update();
1551
- }
1552
- async onOffer(message) {
1553
- log5("offer", {
1554
- message
1555
- }, {
1556
- F: __dxlog_file5,
1557
- L: 206,
1558
- S: this,
1559
- C: (f, a) => f(...a)
1560
- });
1561
- if (this._ctx.disposed) {
1562
- log5("ignored for disposed swarm", void 0, {
1563
- F: __dxlog_file5,
1564
- L: 208,
1565
- S: this,
1566
- C: (f, a) => f(...a)
1567
- });
1568
- return {
1569
- accept: false
1570
- };
1571
- }
1572
- invariant4(message.author, void 0, {
1573
- F: __dxlog_file5,
1574
- L: 213,
1575
- S: this,
1576
- A: [
1577
- "message.author",
1578
- ""
1579
- ]
1580
- });
1581
- if (message.recipient.peerKey !== this._ownPeer.peerKey) {
1582
- log5("rejecting offer with incorrect peerId", {
1583
- message
1584
- }, {
1585
- F: __dxlog_file5,
1586
- L: 215,
1587
- S: this,
1588
- C: (f, a) => f(...a)
1589
- });
1590
- return {
1591
- accept: false
1592
- };
1593
- }
1594
- if (!message.topic?.equals(this._topic)) {
1595
- log5("rejecting offer with incorrect topic", {
1596
- message
1597
- }, {
1598
- F: __dxlog_file5,
1599
- L: 219,
1600
- S: this,
1601
- C: (f, a) => f(...a)
1602
- });
1603
- return {
1604
- accept: false
1605
- };
1606
- }
1607
- const peer = this._getOrCreatePeer(message.author);
1608
- const answer = await peer.onOffer(message);
1609
- this._topology.update();
1610
- return answer;
1611
- }
1612
- async onSignal(message) {
1613
- log5("signal", {
1614
- message
1615
- }, {
1616
- F: __dxlog_file5,
1617
- L: 230,
1618
- S: this,
1619
- C: (f, a) => f(...a)
1620
- });
1621
- if (this._ctx.disposed) {
1622
- log5.info("ignored for offline swarm", void 0, {
1623
- F: __dxlog_file5,
1624
- L: 232,
1625
- S: this,
1626
- C: (f, a) => f(...a)
1627
- });
1628
- return;
1629
- }
1630
- invariant4(message.recipient.peerKey === this._ownPeer.peerKey, `Invalid signal peer id expected=${this.ownPeerId}, actual=${message.recipient}`, {
1631
- F: __dxlog_file5,
1632
- L: 235,
1633
- S: this,
1634
- A: [
1635
- "message.recipient.peerKey === this._ownPeer.peerKey",
1636
- "`Invalid signal peer id expected=${this.ownPeerId}, actual=${message.recipient}`"
1637
- ]
1638
- });
1639
- invariant4(message.topic?.equals(this._topic), void 0, {
1640
- F: __dxlog_file5,
1641
- L: 239,
1642
- S: this,
1643
- A: [
1644
- "message.topic?.equals(this._topic)",
1645
- ""
1646
- ]
1647
- });
1648
- invariant4(message.author, void 0, {
1649
- F: __dxlog_file5,
1650
- L: 240,
1651
- S: this,
1652
- A: [
1653
- "message.author",
1654
- ""
1655
- ]
1656
- });
1657
- const peer = this._getOrCreatePeer(message.author);
1658
- await peer.onSignal(message);
1659
- }
1660
- // For debug purposes
1661
- async goOffline() {
1662
- await this._ctx.dispose();
1663
- await Promise.all([
1664
- ...this._peers.keys()
1665
- ].map((peerId) => this._destroyPeer(peerId, "goOffline")));
1666
- }
1667
- // For debug purposes
1668
- async goOnline() {
1669
- this._ctx = new Context4(void 0, {
1670
- F: __dxlog_file5,
1671
- L: 256
1672
- });
1673
- }
1674
- _getOrCreatePeer(peerInfo) {
1675
- invariant4(peerInfo.peerKey, "PeerInfo.peerKey is required", {
1676
- F: __dxlog_file5,
1677
- L: 260,
1678
- S: this,
1679
- A: [
1680
- "peerInfo.peerKey",
1681
- "'PeerInfo.peerKey is required'"
1682
- ]
1683
- });
1684
- let peer = this._peers.get(peerInfo);
1685
- if (!peer) {
1686
- peer = new Peer(peerInfo, this._topic, this._ownPeer, this._swarmMessenger, this._protocolProvider, this._transportFactory, this._connectionLimiter, {
1687
- onInitiated: (connection) => {
1688
- this.connectionAdded.emit(connection);
1689
- },
1690
- onConnected: () => {
1691
- this.connected.emit(peerInfo);
1692
- },
1693
- onDisconnected: async () => {
1694
- if (this._isUnregistered(peer)) {
1695
- return;
1696
- }
1697
- if (!peer.advertizing) {
1698
- await this._destroyPeer(peerInfo, "peer disconnected");
1699
- }
1700
- this.disconnected.emit(peerInfo);
1701
- this._topology.update();
1702
- },
1703
- onRejected: () => {
1704
- if (!this._isUnregistered(peer)) {
1705
- log5("peer rejected connection", {
1706
- peerInfo
1707
- }, {
1708
- F: __dxlog_file5,
1709
- L: 293,
1710
- S: this,
1711
- C: (f, a) => f(...a)
1712
- });
1713
- void this._destroyPeer(peerInfo, "peer rejected connection");
1714
- }
1715
- },
1716
- onAccepted: () => {
1717
- this._topology.update();
1718
- },
1719
- onOffer: (remoteId) => {
1720
- return this._topology.onOffer(PublicKey4.from(remoteId.peerKey));
1721
- },
1722
- onPeerAvailable: () => {
1723
- this._topology.update();
1724
- }
1725
- });
1726
- this._peers.set(peerInfo, peer);
1727
- }
1728
- return peer;
1729
- }
1730
- async _destroyPeer(peerInfo, reason) {
1731
- const peer = this._peers.get(peerInfo);
1732
- invariant4(peer, void 0, {
1733
- F: __dxlog_file5,
1734
- L: 316,
1735
- S: this,
1736
- A: [
1737
- "peer",
1738
- ""
1739
- ]
1740
- });
1741
- this._peers.delete(peerInfo);
1742
- await peer.safeDestroy(new Error(reason));
1743
- }
1744
- _getSwarmController() {
1745
- return {
1746
- getState: () => ({
1747
- ownPeerId: PublicKey4.from(this._ownPeer.peerKey),
1748
- connected: Array.from(this._peers.entries()).filter(([_, peer]) => peer.connection).map(([info]) => PublicKey4.from(info.peerKey)),
1749
- candidates: Array.from(this._peers.entries()).filter(([_, peer]) => !peer.connection && peer.advertizing && peer.availableToConnect).map(([info]) => PublicKey4.from(info.peerKey)),
1750
- allPeers: Array.from(this._peers.keys()).map((info) => PublicKey4.from(info.peerKey))
1751
- }),
1752
- connect: (peer) => {
1753
- if (this._ctx.disposed) {
1754
- return;
1755
- }
1756
- scheduleTask3(this._ctx, async () => {
1757
- try {
1758
- await this._initiateConnection({
1759
- peerKey: peer.toHex()
1760
- });
1761
- } catch (err) {
1762
- log5("initiation error", err, {
1763
- F: __dxlog_file5,
1764
- L: 343,
1765
- S: this,
1766
- C: (f, a) => f(...a)
1767
- });
1768
- }
1769
- });
1770
- },
1771
- disconnect: async (peer) => {
1772
- if (this._ctx.disposed) {
1773
- return;
1774
- }
1775
- scheduleTask3(this._ctx, async () => {
1776
- await this._closeConnection({
1777
- peerKey: peer.toHex()
1778
- });
1779
- this._topology.update();
1780
- });
1781
- }
1782
- };
1783
- }
1784
- /**
1785
- * Creates a connection then sends message over signal network.
1786
- */
1787
- async _initiateConnection(remotePeer) {
1788
- const ctx = this._ctx;
1789
- const peer = this._getOrCreatePeer(remotePeer);
1790
- if (remotePeer.peerKey < this._ownPeer.peerKey) {
1791
- log5("initiation delay", {
1792
- remotePeer
1793
- }, {
1794
- F: __dxlog_file5,
1795
- L: 371,
1796
- S: this,
1797
- C: (f, a) => f(...a)
1798
- });
1799
- await sleep2(this._initiationDelay);
1800
- }
1801
- if (ctx.disposed) {
1802
- return;
1803
- }
1804
- if (this._isUnregistered(peer)) {
1805
- throw new Error("Peer left during initiation delay");
1806
- }
1807
- if (peer.connection) {
1808
- return;
1809
- }
1810
- log5("initiating connection...", {
1811
- remotePeer
1812
- }, {
1813
- F: __dxlog_file5,
1814
- L: 387,
1815
- S: this,
1816
- C: (f, a) => f(...a)
1817
- });
1818
- await peer.initiateConnection();
1819
- this._topology.update();
1820
- log5("initiated", {
1821
- remotePeer
1822
- }, {
1823
- F: __dxlog_file5,
1824
- L: 390,
1825
- S: this,
1826
- C: (f, a) => f(...a)
1827
- });
1828
- }
1829
- async _closeConnection(peerInfo) {
1830
- const peer = this._peers.get(peerInfo);
1831
- if (!peer) {
1832
- return;
1833
- }
1834
- await peer.closeConnection();
1835
- }
1836
- _isUnregistered(peer) {
1837
- return !peer || this._peers.get(peer.remoteInfo) !== peer;
1838
- }
1839
- };
1840
- _ts_decorate3([
1841
- logInfo2
1842
- ], Swarm.prototype, "_instanceId", void 0);
1843
- _ts_decorate3([
1844
- logInfo2
1845
- ], Swarm.prototype, "ownPeer", null);
1846
- _ts_decorate3([
1847
- logInfo2
1848
- ], Swarm.prototype, "topic", null);
1849
- _ts_decorate3([
1850
- synchronized3
1851
- ], Swarm.prototype, "onSwarmEvent", null);
1852
- _ts_decorate3([
1853
- synchronized3
1854
- ], Swarm.prototype, "onOffer", null);
1855
- _ts_decorate3([
1856
- synchronized3
1857
- ], Swarm.prototype, "goOffline", null);
1858
- _ts_decorate3([
1859
- synchronized3
1860
- ], Swarm.prototype, "goOnline", null);
1861
-
1862
- // packages/core/mesh/network-manager/src/swarm/swarm-mapper.ts
1863
- import { Event as Event4, EventSubscriptions } from "@dxos/async";
1864
- import { PublicKey as PublicKey5 } from "@dxos/keys";
1865
- import { log as log6 } from "@dxos/log";
1866
- import { PeerInfoHash as PeerInfoHash2 } from "@dxos/messaging";
1867
- import { ComplexMap as ComplexMap3 } from "@dxos/util";
1868
- var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/swarm/swarm-mapper.ts";
1869
- var SwarmMapper = class {
1870
- get peers() {
1871
- return Array.from(this._peers.values());
1872
- }
1873
- constructor(_swarm) {
1874
- this._swarm = _swarm;
1875
- this._subscriptions = new EventSubscriptions();
1876
- this._connectionSubscriptions = new ComplexMap3(PeerInfoHash2);
1877
- this._peers = new ComplexMap3(PeerInfoHash2);
1878
- this.mapUpdated = new Event4();
1879
- this._subscriptions.add(_swarm.connectionAdded.on((connection) => {
1880
- this._update();
1881
- this._connectionSubscriptions.set(connection.remoteInfo, connection.stateChanged.on(() => {
1882
- this._update();
1883
- }));
1884
- }));
1885
- this._subscriptions.add(_swarm.disconnected.on((peerId) => {
1886
- this._connectionSubscriptions.get(peerId)?.();
1887
- this._connectionSubscriptions.delete(peerId);
1888
- this._update();
1889
- }));
1890
- this._update();
1891
- }
1892
- _update() {
1893
- log6("updating swarm", void 0, {
1894
- F: __dxlog_file6,
1895
- L: 73,
1896
- S: this,
1897
- C: (f, a) => f(...a)
1898
- });
1899
- this._peers.clear();
1900
- this._peers.set(this._swarm.ownPeer, {
1901
- id: this._swarm.ownPeerId,
1902
- state: "ME",
1903
- connections: []
1904
- });
1905
- for (const connection of this._swarm.connections) {
1906
- this._peers.set(connection.remoteInfo, {
1907
- id: PublicKey5.from(connection.remoteInfo.peerKey),
1908
- state: connection.state,
1909
- connections: [
1910
- this._swarm.ownPeerId
1911
- ]
1912
- });
1913
- }
1914
- log6("graph changed", {
1915
- directConnections: this._swarm.connections.length,
1916
- totalPeersInSwarm: this._peers.size
1917
- }, {
1918
- F: __dxlog_file6,
1919
- L: 114,
1920
- S: this,
1921
- C: (f, a) => f(...a)
1922
- });
1923
- this.mapUpdated.emit(Array.from(this._peers.values()));
1924
- }
1925
- // TODO(burdon): Async open/close.
1926
- destroy() {
1927
- Array.from(this._connectionSubscriptions.values()).forEach((cb) => cb());
1928
- this._subscriptions.clear();
1929
- }
1930
- };
1931
-
1932
- // packages/core/mesh/network-manager/src/swarm/connection-limiter.ts
1933
- import { DeferredTask as DeferredTask2 } from "@dxos/async";
1934
- import { Context as Context5 } from "@dxos/context";
1935
- import { invariant as invariant5 } from "@dxos/invariant";
1936
- import { PublicKey as PublicKey6 } from "@dxos/keys";
1937
- import { log as log7 } from "@dxos/log";
1938
- import { CancelledError as CancelledError3 } from "@dxos/protocols";
1939
- import { ComplexMap as ComplexMap4 } from "@dxos/util";
1940
- var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/swarm/connection-limiter.ts";
1941
- var MAX_CONCURRENT_INITIATING_CONNECTIONS = 50;
1942
- var ConnectionLimiter = class {
1943
- constructor({ maxConcurrentInitConnections = MAX_CONCURRENT_INITIATING_CONNECTIONS } = {}) {
1944
- this._ctx = new Context5(void 0, {
1945
- F: __dxlog_file7,
1946
- L: 23
1947
- });
1948
- /**
1949
- * Queue of promises to resolve when initiating connections amount is below the limit.
1950
- */
1951
- this._waitingPromises = new ComplexMap4(PublicKey6.hash);
1952
- this.resolveWaitingPromises = new DeferredTask2(this._ctx, async () => {
1953
- Array.from(this._waitingPromises.values()).slice(0, this._maxConcurrentInitConnections).forEach(({ resolve }) => {
1954
- resolve();
1955
- });
1956
- });
1957
- this._maxConcurrentInitConnections = maxConcurrentInitConnections;
1958
- }
1959
- /**
1960
- * @returns Promise that resolves in queue when connections amount with 'CONNECTING' state is below the limit.
1961
- */
1962
- async connecting(sessionId) {
1963
- invariant5(!this._waitingPromises.has(sessionId), "Peer is already waiting for connection", {
1964
- F: __dxlog_file7,
1965
- L: 48,
1966
- S: this,
1967
- A: [
1968
- "!this._waitingPromises.has(sessionId)",
1969
- "'Peer is already waiting for connection'"
1970
- ]
1971
- });
1972
- log7("waiting", {
1973
- sessionId
1974
- }, {
1975
- F: __dxlog_file7,
1976
- L: 49,
1977
- S: this,
1978
- C: (f, a) => f(...a)
1979
- });
1980
- await new Promise((resolve, reject) => {
1981
- this._waitingPromises.set(sessionId, {
1982
- resolve,
1983
- reject
1984
- });
1985
- this.resolveWaitingPromises.schedule();
1986
- });
1987
- log7("allow", {
1988
- sessionId
1989
- }, {
1990
- F: __dxlog_file7,
1991
- L: 57,
1992
- S: this,
1993
- C: (f, a) => f(...a)
1994
- });
1995
- }
1996
- /**
1997
- * Rejects promise returned by `connecting` method.
1998
- */
1999
- doneConnecting(sessionId) {
2000
- log7("done", {
2001
- sessionId
2002
- }, {
2003
- F: __dxlog_file7,
2004
- L: 64,
2005
- S: this,
2006
- C: (f, a) => f(...a)
2007
- });
2008
- if (!this._waitingPromises.has(sessionId)) {
2009
- return;
2010
- }
2011
- this._waitingPromises.get(sessionId).reject(new CancelledError3());
2012
- this._waitingPromises.delete(sessionId);
2013
- this.resolveWaitingPromises.schedule();
2014
- }
2015
- };
2016
-
2017
- // packages/core/mesh/network-manager/src/connection-log.ts
2018
- import { Event as Event5 } from "@dxos/async";
2019
- import { raise } from "@dxos/debug";
2020
- import { PublicKey as PublicKey7 } from "@dxos/keys";
2021
- import { ComplexMap as ComplexMap5 } from "@dxos/util";
2022
- var CONNECTION_GC_THRESHOLD = 1e3 * 60 * 15;
2023
- var EventType;
2024
- (function(EventType2) {
2025
- EventType2["CONNECTION_STATE_CHANGED"] = "CONNECTION_STATE_CHANGED";
2026
- EventType2["PROTOCOL_ERROR"] = "PROTOCOL_ERROR";
2027
- EventType2["PROTOCOL_EXTENSIONS_INITIALIZED"] = "PROTOCOL_EXTENSIONS_INITIALIZED";
2028
- EventType2["PROTOCOL_EXTENSIONS_HANDSHAKE"] = "PROTOCOL_EXTENSIONS_HANDSHAKE";
2029
- EventType2["PROTOCOL_HANDSHAKE"] = "PROTOCOL_HANDSHAKE";
2030
- })(EventType || (EventType = {}));
2031
- var ConnectionLog = class {
2032
- constructor() {
2033
- /**
2034
- * SwarmId => info
2035
- */
2036
- this._swarms = new ComplexMap5(PublicKey7.hash);
2037
- this.update = new Event5();
2038
- }
2039
- getSwarmInfo(swarmId) {
2040
- return this._swarms.get(swarmId) ?? raise(new Error(`Swarm not found: ${swarmId}`));
2041
- }
2042
- get swarms() {
2043
- return Array.from(this._swarms.values());
2044
- }
2045
- joinedSwarm(swarm) {
2046
- const info = {
2047
- id: PublicKey7.from(swarm._instanceId),
2048
- topic: swarm.topic,
2049
- isActive: true,
2050
- label: swarm.label,
2051
- connections: []
2052
- };
2053
- this._swarms.set(PublicKey7.from(swarm._instanceId), info);
2054
- this.update.emit();
2055
- swarm.connectionAdded.on((connection) => {
2056
- const connectionInfo = {
2057
- state: ConnectionState.CREATED,
2058
- closeReason: connection.closeReason,
2059
- remotePeerId: PublicKey7.from(connection.remoteInfo.peerKey),
2060
- sessionId: connection.sessionId,
2061
- transport: connection.transport && Object.getPrototypeOf(connection.transport).constructor.name,
2062
- protocolExtensions: [],
2063
- events: [],
2064
- lastUpdate: /* @__PURE__ */ new Date()
2065
- };
2066
- info.connections.push(connectionInfo);
2067
- this.update.emit();
2068
- connection.stateChanged.on(async (state) => {
2069
- connectionInfo.state = state;
2070
- connectionInfo.closeReason = connection.closeReason;
2071
- connectionInfo.lastUpdate = /* @__PURE__ */ new Date();
2072
- connectionInfo.events.push({
2073
- type: "CONNECTION_STATE_CHANGED",
2074
- newState: state
2075
- });
2076
- if (state === ConnectionState.CONNECTED) {
2077
- const details = await connection.transport?.getDetails();
2078
- connectionInfo.transportDetails = details;
2079
- }
2080
- this.update.emit();
2081
- });
2082
- connection.protocol?.stats?.on((stats) => {
2083
- connectionInfo.readBufferSize = stats.readBufferSize;
2084
- connectionInfo.writeBufferSize = stats.writeBufferSize;
2085
- connectionInfo.streams = stats.channels;
2086
- connectionInfo.lastUpdate = /* @__PURE__ */ new Date();
2087
- this.update.emit();
2088
- });
2089
- connection.transportStats?.on((stats) => {
2090
- connectionInfo.transportBytesSent = stats.bytesSent;
2091
- connectionInfo.transportBytesReceived = stats.bytesReceived;
2092
- connectionInfo.transportPacketsSent = stats.packetsSent;
2093
- connectionInfo.transportPacketsReceived = stats.packetsReceived;
2094
- });
2095
- gcSwarm(info);
2096
- });
2097
- }
2098
- leftSwarm(swarm) {
2099
- this.getSwarmInfo(PublicKey7.from(swarm._instanceId)).isActive = false;
2100
- this.update.emit();
2101
- }
2102
- };
2103
- var gcSwarm = (swarm) => {
2104
- swarm.connections = swarm.connections?.filter((connection) => {
2105
- return connection.lastUpdate ? Date.now() - connection.lastUpdate.getTime() < CONNECTION_GC_THRESHOLD : true;
2106
- });
2107
- };
2108
-
2109
- // packages/core/mesh/network-manager/src/network-manager.ts
2110
- import { Event as Event6, synchronized as synchronized4 } from "@dxos/async";
2111
- import { invariant as invariant6 } from "@dxos/invariant";
2112
- import { PublicKey as PublicKey8 } from "@dxos/keys";
2113
- import { log as log8 } from "@dxos/log";
2114
- import { Messenger } from "@dxos/messaging";
2115
- import { trace as trace3 } from "@dxos/protocols";
2116
- import { ConnectionState as ConnectionState2 } from "@dxos/protocols/proto/dxos/client/services";
2117
- import { ComplexMap as ComplexMap6 } from "@dxos/util";
2118
- function _ts_decorate4(decorators, target, key, desc) {
2119
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2120
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2121
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
2122
- return c > 3 && r && Object.defineProperty(target, key, r), r;
2123
- }
2124
- var __dxlog_file8 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/network-manager.ts";
2125
- var SwarmNetworkManager = class {
2126
- constructor({ transportFactory, signalManager, enableDevtoolsLogging, peerInfo }) {
2127
- /**
2128
- * @internal
2129
- */
2130
- this._swarms = new ComplexMap6(PublicKey8.hash);
2131
- this._mappers = new ComplexMap6(PublicKey8.hash);
2132
- this._instanceId = PublicKey8.random().toHex();
2133
- this._peerInfo = void 0;
2134
- this._connectionState = ConnectionState2.ONLINE;
2135
- this.connectionStateChanged = new Event6();
2136
- this.topicsUpdated = new Event6();
2137
- this._transportFactory = transportFactory;
2138
- this._signalManager = signalManager;
2139
- this._signalManager.swarmEvent.on((event) => this._swarms.get(event.topic)?.onSwarmEvent(event));
2140
- this._messenger = new Messenger({
2141
- signalManager: this._signalManager
2142
- });
2143
- this._signalConnection = {
2144
- join: (opts) => this._signalManager.join(opts),
2145
- leave: (opts) => this._signalManager.leave(opts)
2146
- };
2147
- this._peerInfo = peerInfo;
2148
- this._connectionLimiter = new ConnectionLimiter();
2149
- if (enableDevtoolsLogging) {
2150
- this._connectionLog = new ConnectionLog();
2151
- }
2152
- }
2153
- // TODO(burdon): Remove access (Devtools only).
2154
- get connectionLog() {
2155
- return this._connectionLog;
2156
- }
2157
- get connectionState() {
2158
- return this._connectionState;
2159
- }
2160
- // TODO(burdon): Reconcile with "discovery_key".
2161
- get topics() {
2162
- return Array.from(this._swarms.keys());
2163
- }
2164
- getSwarmMap(topic) {
2165
- return this._mappers.get(topic);
2166
- }
2167
- getSwarm(topic) {
2168
- return this._swarms.get(topic);
2169
- }
2170
- setPeerInfo(peerInfo) {
2171
- this._peerInfo = peerInfo;
2172
- }
2173
- async open() {
2174
- log8.trace("dxos.mesh.network-manager.open", trace3.begin({
2175
- id: this._instanceId
2176
- }), {
2177
- F: __dxlog_file8,
2178
- L: 133,
2179
- S: this,
2180
- C: (f, a) => f(...a)
2181
- });
2182
- await this._messenger.open();
2183
- await this._signalManager.open();
2184
- log8.trace("dxos.mesh.network-manager.open", trace3.end({
2185
- id: this._instanceId
2186
- }), {
2187
- F: __dxlog_file8,
2188
- L: 136,
2189
- S: this,
2190
- C: (f, a) => f(...a)
2191
- });
2192
- }
2193
- async close() {
2194
- for (const topic of this._swarms.keys()) {
2195
- await this.leaveSwarm(topic).catch((err) => {
2196
- log8(err, void 0, {
2197
- F: __dxlog_file8,
2198
- L: 142,
2199
- S: this,
2200
- C: (f, a) => f(...a)
2201
- });
2202
- });
2203
- }
2204
- await this._messenger.close();
2205
- await this._signalManager.close();
2206
- }
2207
- /**
2208
- * Join the swarm.
2209
- */
2210
- async joinSwarm({ topic, peerInfo, topology, protocolProvider: protocol, label }) {
2211
- invariant6(PublicKey8.isPublicKey(topic), void 0, {
2212
- F: __dxlog_file8,
2213
- L: 161,
2214
- S: this,
2215
- A: [
2216
- "PublicKey.isPublicKey(topic)",
2217
- ""
2218
- ]
2219
- });
2220
- if (!peerInfo) {
2221
- peerInfo = {
2222
- peerKey: this._peerInfo?.peerKey ?? PublicKey8.random().toHex(),
2223
- identityKey: this._peerInfo?.identityKey ?? PublicKey8.random().toHex()
2224
- };
2225
- }
2226
- invariant6(PublicKey8.from(peerInfo.peerKey), void 0, {
2227
- F: __dxlog_file8,
2228
- L: 168,
2229
- S: this,
2230
- A: [
2231
- "PublicKey.from(peerInfo.peerKey)",
2232
- ""
2233
- ]
2234
- });
2235
- invariant6(PublicKey8.from(peerInfo.identityKey), void 0, {
2236
- F: __dxlog_file8,
2237
- L: 169,
2238
- S: this,
2239
- A: [
2240
- "PublicKey.from(peerInfo.identityKey!)",
2241
- ""
2242
- ]
2243
- });
2244
- invariant6(topology, void 0, {
2245
- F: __dxlog_file8,
2246
- L: 170,
2247
- S: this,
2248
- A: [
2249
- "topology",
2250
- ""
2251
- ]
2252
- });
2253
- invariant6(typeof protocol === "function", void 0, {
2254
- F: __dxlog_file8,
2255
- L: 171,
2256
- S: this,
2257
- A: [
2258
- "typeof protocol === 'function'",
2259
- ""
2260
- ]
2261
- });
2262
- if (this._swarms.has(topic)) {
2263
- throw new Error(`Already connected to swarm: ${PublicKey8.from(topic)}`);
2264
- }
2265
- log8("joining", {
2266
- topic: PublicKey8.from(topic),
2267
- peerInfo,
2268
- topology: topology.toString()
2269
- }, {
2270
- F: __dxlog_file8,
2271
- L: 176,
2272
- S: this,
2273
- C: (f, a) => f(...a)
2274
- });
2275
- const swarm = new Swarm(topic, peerInfo, topology, protocol, this._messenger, this._transportFactory, label, this._connectionLimiter);
2276
- swarm.errors.handle((error) => {
2277
- log8("swarm error", {
2278
- error
2279
- }, {
2280
- F: __dxlog_file8,
2281
- L: 189,
2282
- S: this,
2283
- C: (f, a) => f(...a)
2284
- });
2285
- });
2286
- this._swarms.set(topic, swarm);
2287
- this._mappers.set(topic, new SwarmMapper(swarm));
2288
- await swarm.open();
2289
- this._signalConnection.join({
2290
- topic,
2291
- peer: peerInfo
2292
- }).catch((error) => log8.catch(error, void 0, {
2293
- F: __dxlog_file8,
2294
- L: 198,
2295
- S: this,
2296
- C: (f, a) => f(...a)
2297
- }));
2298
- this.topicsUpdated.emit();
2299
- this._connectionLog?.joinedSwarm(swarm);
2300
- log8("joined", {
2301
- topic: PublicKey8.from(topic),
2302
- count: this._swarms.size
2303
- }, {
2304
- F: __dxlog_file8,
2305
- L: 202,
2306
- S: this,
2307
- C: (f, a) => f(...a)
2308
- });
2309
- return {
2310
- close: () => this.leaveSwarm(topic)
2311
- };
2312
- }
2313
- /**
2314
- * Close the connection.
2315
- */
2316
- async leaveSwarm(topic) {
2317
- if (!this._swarms.has(topic)) {
2318
- return;
2319
- }
2320
- log8("leaving", {
2321
- topic: PublicKey8.from(topic)
2322
- }, {
2323
- F: __dxlog_file8,
2324
- L: 219,
2325
- S: this,
2326
- C: (f, a) => f(...a)
2327
- });
2328
- const swarm = this._swarms.get(topic);
2329
- await this._signalConnection.leave({
2330
- topic,
2331
- peer: swarm.ownPeer
2332
- });
2333
- const map = this._mappers.get(topic);
2334
- map.destroy();
2335
- this._mappers.delete(topic);
2336
- this._connectionLog?.leftSwarm(swarm);
2337
- await swarm.destroy();
2338
- this._swarms.delete(topic);
2339
- this.topicsUpdated.emit();
2340
- log8("left", {
2341
- topic: PublicKey8.from(topic),
2342
- count: this._swarms.size
2343
- }, {
2344
- F: __dxlog_file8,
2345
- L: 233,
2346
- S: this,
2347
- C: (f, a) => f(...a)
2348
- });
2349
- }
2350
- async setConnectionState(state) {
2351
- if (state === this._connectionState) {
2352
- return;
2353
- }
2354
- switch (state) {
2355
- case ConnectionState2.OFFLINE: {
2356
- this._connectionState = state;
2357
- await Promise.all([
2358
- ...this._swarms.values()
2359
- ].map((swarm) => swarm.goOffline()));
2360
- await this._messenger.close();
2361
- await this._signalManager.close();
2362
- break;
2363
- }
2364
- case ConnectionState2.ONLINE: {
2365
- this._connectionState = state;
2366
- this._messenger.open();
2367
- await Promise.all([
2368
- ...this._swarms.values()
2369
- ].map((swarm) => swarm.goOnline()));
2370
- await this._signalManager.open();
2371
- break;
2372
- }
2373
- }
2374
- this.connectionStateChanged.emit(this._connectionState);
2375
- }
2376
- };
2377
- _ts_decorate4([
2378
- synchronized4
2379
- ], SwarmNetworkManager.prototype, "joinSwarm", null);
2380
- _ts_decorate4([
2381
- synchronized4
2382
- ], SwarmNetworkManager.prototype, "leaveSwarm", null);
2383
-
2384
- // packages/core/mesh/network-manager/src/topology/fully-connected-topology.ts
2385
- import { invariant as invariant7 } from "@dxos/invariant";
2386
- var __dxlog_file9 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/topology/fully-connected-topology.ts";
2387
- var FullyConnectedTopology = class {
2388
- toString() {
2389
- return "FullyConnectedTopology";
2390
- }
2391
- init(controller) {
2392
- invariant7(!this._controller, "Already initialized", {
2393
- F: __dxlog_file9,
2394
- L: 18,
2395
- S: this,
2396
- A: [
2397
- "!this._controller",
2398
- "'Already initialized'"
2399
- ]
2400
- });
2401
- this._controller = controller;
2402
- }
2403
- update() {
2404
- invariant7(this._controller, "Not initialized", {
2405
- F: __dxlog_file9,
2406
- L: 23,
2407
- S: this,
2408
- A: [
2409
- "this._controller",
2410
- "'Not initialized'"
2411
- ]
2412
- });
2413
- const { candidates: discovered } = this._controller.getState();
2414
- for (const peer of discovered) {
2415
- this._controller.connect(peer);
2416
- }
2417
- }
2418
- async onOffer(peer) {
2419
- return true;
2420
- }
2421
- async destroy() {
2422
- }
2423
- };
2424
-
2425
- // packages/core/mesh/network-manager/src/topology/mmst-topology.ts
2426
- import { invariant as invariant8 } from "@dxos/invariant";
2427
- import { log as log9 } from "@dxos/log";
2428
- var __dxlog_file10 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/topology/mmst-topology.ts";
2429
- var MIN_UPDATE_INTERVAL = 1e3 * 10;
2430
- var MAX_CHANGES_PER_UPDATE = 1;
2431
- var MMSTTopology = class {
2432
- constructor({ originateConnections = 2, maxPeers = 4, sampleSize = 10 } = {}) {
2433
- this._sampleCollected = false;
2434
- this._lastAction = /* @__PURE__ */ new Date(0);
2435
- this._originateConnections = originateConnections;
2436
- this._maxPeers = maxPeers;
2437
- this._sampleSize = sampleSize;
2438
- }
2439
- init(controller) {
2440
- invariant8(!this._controller, "Already initialized", {
2441
- F: __dxlog_file10,
2442
- L: 49,
2443
- S: this,
2444
- A: [
2445
- "!this._controller",
2446
- "'Already initialized'"
2447
- ]
2448
- });
2449
- this._controller = controller;
2450
- }
2451
- update() {
2452
- invariant8(this._controller, "Not initialized", {
2453
- F: __dxlog_file10,
2454
- L: 54,
2455
- S: this,
2456
- A: [
2457
- "this._controller",
2458
- "'Not initialized'"
2459
- ]
2460
- });
2461
- const { connected, candidates } = this._controller.getState();
2462
- if (this._sampleCollected || connected.length > this._maxPeers || candidates.length > 0) {
2463
- log9("Running the algorithm.", void 0, {
2464
- F: __dxlog_file10,
2465
- L: 58,
2466
- S: this,
2467
- C: (f, a) => f(...a)
2468
- });
2469
- this._sampleCollected = true;
2470
- this._runAlgorithm();
2471
- }
2472
- }
2473
- forceUpdate() {
2474
- this._lastAction = /* @__PURE__ */ new Date(0);
2475
- this.update();
2476
- }
2477
- async onOffer(peer) {
2478
- invariant8(this._controller, "Not initialized", {
2479
- F: __dxlog_file10,
2480
- L: 70,
2481
- S: this,
2482
- A: [
2483
- "this._controller",
2484
- "'Not initialized'"
2485
- ]
2486
- });
2487
- const { connected } = this._controller.getState();
2488
- const accept = connected.length < this._maxPeers;
2489
- log9(`Offer ${peer} accept=${accept}`, void 0, {
2490
- F: __dxlog_file10,
2491
- L: 73,
2492
- S: this,
2493
- C: (f, a) => f(...a)
2494
- });
2495
- return accept;
2496
- }
2497
- async destroy() {
2498
- }
2499
- _runAlgorithm() {
2500
- invariant8(this._controller, "Not initialized", {
2501
- F: __dxlog_file10,
2502
- L: 82,
2503
- S: this,
2504
- A: [
2505
- "this._controller",
2506
- "'Not initialized'"
2507
- ]
2508
- });
2509
- const { connected, candidates, ownPeerId } = this._controller.getState();
2510
- if (connected.length > this._maxPeers) {
2511
- log9(`disconnect ${connected.length - this._maxPeers} peers.`, void 0, {
2512
- F: __dxlog_file10,
2513
- L: 88,
2514
- S: this,
2515
- C: (f, a) => f(...a)
2516
- });
2517
- const sorted = sortByXorDistance(connected, ownPeerId).reverse().slice(0, this._maxPeers - connected.length);
2518
- invariant8(sorted.length === 0, void 0, {
2519
- F: __dxlog_file10,
2520
- L: 92,
2521
- S: this,
2522
- A: [
2523
- "sorted.length === 0",
2524
- ""
2525
- ]
2526
- });
2527
- if (sorted.length > MAX_CHANGES_PER_UPDATE) {
2528
- log9(`want to disconnect ${sorted.length} peers but limited to ${MAX_CHANGES_PER_UPDATE}`, void 0, {
2529
- F: __dxlog_file10,
2530
- L: 95,
2531
- S: this,
2532
- C: (f, a) => f(...a)
2533
- });
2534
- }
2535
- if (Date.now() - this._lastAction.getTime() > MIN_UPDATE_INTERVAL) {
2536
- for (const peer of sorted.slice(0, MAX_CHANGES_PER_UPDATE)) {
2537
- log9(`Disconnect ${peer}.`, void 0, {
2538
- F: __dxlog_file10,
2539
- L: 100,
2540
- S: this,
2541
- C: (f, a) => f(...a)
2542
- });
2543
- this._controller.disconnect(peer);
2544
- }
2545
- this._lastAction = /* @__PURE__ */ new Date();
2546
- } else {
2547
- log9("rate limited disconnect", void 0, {
2548
- F: __dxlog_file10,
2549
- L: 105,
2550
- S: this,
2551
- C: (f, a) => f(...a)
2552
- });
2553
- }
2554
- } else if (connected.length < this._originateConnections) {
2555
- log9(`connect ${this._originateConnections - connected.length} peers.`, void 0, {
2556
- F: __dxlog_file10,
2557
- L: 109,
2558
- S: this,
2559
- C: (f, a) => f(...a)
2560
- });
2561
- const sample = candidates.sort(() => Math.random() - 0.5).slice(0, this._sampleSize);
2562
- const sorted = sortByXorDistance(sample, ownPeerId).slice(0, this._originateConnections - connected.length);
2563
- if (sorted.length > MAX_CHANGES_PER_UPDATE) {
2564
- log9(`want to connect ${sorted.length} peers but limited to ${MAX_CHANGES_PER_UPDATE}`, void 0, {
2565
- F: __dxlog_file10,
2566
- L: 114,
2567
- S: this,
2568
- C: (f, a) => f(...a)
2569
- });
2570
- }
2571
- if (Date.now() - this._lastAction.getTime() > MIN_UPDATE_INTERVAL) {
2572
- for (const peer of sorted.slice(0, MAX_CHANGES_PER_UPDATE)) {
2573
- log9(`Connect ${peer}.`, void 0, {
2574
- F: __dxlog_file10,
2575
- L: 118,
2576
- S: this,
2577
- C: (f, a) => f(...a)
2578
- });
2579
- this._controller.connect(peer);
2580
- }
2581
- this._lastAction = /* @__PURE__ */ new Date();
2582
- } else {
2583
- log9("rate limited connect", void 0, {
2584
- F: __dxlog_file10,
2585
- L: 123,
2586
- S: this,
2587
- C: (f, a) => f(...a)
2588
- });
2589
- }
2590
- }
2591
- }
2592
- toString() {
2593
- return "MMSTTopology";
2594
- }
2595
- };
2596
- var sortByXorDistance = (keys, reference) => {
2597
- const sorted = keys.sort((a, b) => {
2598
- return compareXor(distXor(a.asBuffer(), reference.asBuffer()), distXor(b.asBuffer(), reference.asBuffer()));
2599
- });
2600
- log9("Sorted keys", {
2601
- keys,
2602
- reference,
2603
- sorted
2604
- }, {
2605
- F: __dxlog_file10,
2606
- L: 137,
2607
- S: void 0,
2608
- C: (f, a) => f(...a)
2609
- });
2610
- return sorted;
2611
- };
2612
- var distXor = (a, b) => {
2613
- const maxLength = Math.max(a.length, b.length);
2614
- const result = Buffer.allocUnsafe(maxLength);
2615
- for (let i = 0; i < maxLength; i++) {
2616
- result[i] = (a[i] || 0) ^ (b[i] || 0);
2617
- }
2618
- return result;
2619
- };
2620
- var compareXor = (a, b) => {
2621
- const maxLength = Math.max(a.length, b.length);
2622
- for (let i = 0; i < maxLength; i++) {
2623
- if ((a[i] || 0) === (b[i] || 0)) {
2624
- continue;
2625
- }
2626
- return (a[i] || 0) < (b[i] || 0) ? -1 : 1;
2627
- }
2628
- return 0;
2629
- };
2630
-
2631
- // packages/core/mesh/network-manager/src/topology/star-topology.ts
2632
- import { invariant as invariant9 } from "@dxos/invariant";
2633
- import { log as log10 } from "@dxos/log";
2634
- var __dxlog_file11 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/topology/star-topology.ts";
2635
- var StarTopology = class {
2636
- constructor(_centralPeer) {
2637
- this._centralPeer = _centralPeer;
2638
- }
2639
- toString() {
2640
- return `StarTopology(${this._centralPeer.truncate()})`;
2641
- }
2642
- init(controller) {
2643
- invariant9(!this._controller, "Already initialized.", {
2644
- F: __dxlog_file11,
2645
- L: 21,
2646
- S: this,
2647
- A: [
2648
- "!this._controller",
2649
- "'Already initialized.'"
2650
- ]
2651
- });
2652
- this._controller = controller;
2653
- }
2654
- update() {
2655
- invariant9(this._controller, "Not initialized.", {
2656
- F: __dxlog_file11,
2657
- L: 26,
2658
- S: this,
2659
- A: [
2660
- "this._controller",
2661
- "'Not initialized.'"
2662
- ]
2663
- });
2664
- const { candidates, connected, ownPeerId } = this._controller.getState();
2665
- if (!ownPeerId.equals(this._centralPeer)) {
2666
- log10("leaf peer dropping all connections apart from central peer.", void 0, {
2667
- F: __dxlog_file11,
2668
- L: 29,
2669
- S: this,
2670
- C: (f, a) => f(...a)
2671
- });
2672
- for (const peer of connected) {
2673
- if (!peer.equals(this._centralPeer)) {
2674
- log10("dropping connection", {
2675
- peer
2676
- }, {
2677
- F: __dxlog_file11,
2678
- L: 34,
2679
- S: this,
2680
- C: (f, a) => f(...a)
2681
- });
2682
- this._controller.disconnect(peer);
2683
- }
2684
- }
2685
- }
2686
- for (const peer of candidates) {
2687
- if (peer.equals(this._centralPeer) || ownPeerId.equals(this._centralPeer)) {
2688
- log10("connecting to peer", {
2689
- peer
2690
- }, {
2691
- F: __dxlog_file11,
2692
- L: 43,
2693
- S: this,
2694
- C: (f, a) => f(...a)
2695
- });
2696
- this._controller.connect(peer);
2697
- }
2698
- }
2699
- }
2700
- async onOffer(peer) {
2701
- invariant9(this._controller, "Not initialized.", {
2702
- F: __dxlog_file11,
2703
- L: 50,
2704
- S: this,
2705
- A: [
2706
- "this._controller",
2707
- "'Not initialized.'"
2708
- ]
2709
- });
2710
- const { ownPeerId } = this._controller.getState();
2711
- log10("offer", {
2712
- peer,
2713
- isCentral: peer.equals(this._centralPeer),
2714
- isSelfCentral: ownPeerId.equals(this._centralPeer)
2715
- }, {
2716
- F: __dxlog_file11,
2717
- L: 52,
2718
- S: this,
2719
- C: (f, a) => f(...a)
2720
- });
2721
- return ownPeerId.equals(this._centralPeer) || peer.equals(this._centralPeer);
2722
- }
2723
- async destroy() {
2724
- }
2725
- };
2726
-
2727
- // packages/core/mesh/network-manager/src/transport/memory-transport.ts
2728
- import { Transform } from "node:stream";
2729
- import { Event as Event7, Trigger as Trigger2 } from "@dxos/async";
2730
- import { ErrorStream as ErrorStream3 } from "@dxos/debug";
2731
- import { invariant as invariant10 } from "@dxos/invariant";
2732
- import { PublicKey as PublicKey9 } from "@dxos/keys";
2733
- import { log as log11, logInfo as logInfo3 } from "@dxos/log";
2734
- import { ComplexMap as ComplexMap7 } from "@dxos/util";
2735
- function _ts_decorate5(decorators, target, key, desc) {
2736
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2737
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2738
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
2739
- return c > 3 && r && Object.defineProperty(target, key, r), r;
2740
- }
2741
- var __dxlog_file12 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/transport/memory-transport.ts";
2742
- var MEMORY_TRANSPORT_DELAY = 1;
2743
- var createStreamDelay = (delay) => {
2744
- return new Transform({
2745
- objectMode: true,
2746
- transform: (chunk, _, cb) => {
2747
- setTimeout(() => cb(null, chunk), delay);
2748
- }
2749
- });
2750
- };
2751
- var MemoryTransportFactory = {
2752
- createTransport: (options) => new MemoryTransport(options)
2753
- };
2754
- var MemoryTransport = class _MemoryTransport {
2755
- static {
2756
- // TODO(burdon): Remove static properties (inject context into constructor).
2757
- this._connections = new ComplexMap7(PublicKey9.hash);
2758
- }
2759
- constructor(_options) {
2760
- this._options = _options;
2761
- this._instanceId = PublicKey9.random();
2762
- this._remote = new Trigger2();
2763
- this._outgoingDelay = createStreamDelay(MEMORY_TRANSPORT_DELAY);
2764
- this._incomingDelay = createStreamDelay(MEMORY_TRANSPORT_DELAY);
2765
- this._closed = false;
2766
- this.closed = new Event7();
2767
- this.connected = new Event7();
2768
- this.errors = new ErrorStream3();
2769
- invariant10(!_MemoryTransport._connections.has(this._instanceId), "Duplicate memory connection", {
2770
- F: __dxlog_file12,
2771
- L: 64,
2772
- S: this,
2773
- A: [
2774
- "!MemoryTransport._connections.has(this._instanceId)",
2775
- "'Duplicate memory connection'"
2776
- ]
2777
- });
2778
- _MemoryTransport._connections.set(this._instanceId, this);
2779
- }
2780
- get isOpen() {
2781
- return !this._closed;
2782
- }
2783
- async open() {
2784
- log11("opening...", void 0, {
2785
- F: __dxlog_file12,
2786
- L: 74,
2787
- S: this,
2788
- C: (f, a) => f(...a)
2789
- });
2790
- if (this._options.initiator) {
2791
- log11("sending signal", void 0, {
2792
- F: __dxlog_file12,
2793
- L: 78,
2794
- S: this,
2795
- C: (f, a) => f(...a)
2796
- });
2797
- try {
2798
- await this._options.sendSignal({
2799
- payload: {
2800
- transportId: this._instanceId.toHex()
2801
- }
2802
- });
2803
- } catch (err) {
2804
- if (!this._closed) {
2805
- this.errors.raise(toError(err));
2806
- }
2807
- }
2808
- } else {
2809
- this._remote.wait({
2810
- timeout: this._options.timeout ?? 1e3
2811
- }).then((remoteId) => {
2812
- if (this._closed) {
2813
- return;
2814
- }
2815
- this._remoteInstanceId = remoteId;
2816
- this._remoteConnection = _MemoryTransport._connections.get(this._remoteInstanceId);
2817
- if (!this._remoteConnection) {
2818
- this._closed = true;
2819
- this.closed.emit();
2820
- return;
2821
- }
2822
- invariant10(!this._remoteConnection._remoteConnection, `Remote already connected: ${this._remoteInstanceId}`, {
2823
- F: __dxlog_file12,
2824
- L: 104,
2825
- S: this,
2826
- A: [
2827
- "!this._remoteConnection._remoteConnection",
2828
- "`Remote already connected: ${this._remoteInstanceId}`"
2829
- ]
2830
- });
2831
- this._remoteConnection._remoteConnection = this;
2832
- this._remoteConnection._remoteInstanceId = this._instanceId;
2833
- log11("connected", void 0, {
2834
- F: __dxlog_file12,
2835
- L: 108,
2836
- S: this,
2837
- C: (f, a) => f(...a)
2838
- });
2839
- this._options.stream.pipe(this._outgoingDelay).pipe(this._remoteConnection._options.stream).pipe(this._incomingDelay).pipe(this._options.stream);
2840
- this.connected.emit();
2841
- this._remoteConnection.connected.emit();
2842
- }).catch((err) => {
2843
- if (this._closed) {
2844
- return;
2845
- }
2846
- this.errors.raise(err);
2847
- });
2848
- }
2849
- return this;
2850
- }
2851
- async close() {
2852
- log11("closing...", void 0, {
2853
- F: __dxlog_file12,
2854
- L: 130,
2855
- S: this,
2856
- C: (f, a) => f(...a)
2857
- });
2858
- this._closed = true;
2859
- _MemoryTransport._connections.delete(this._instanceId);
2860
- if (this._remoteConnection) {
2861
- this._remoteConnection._closed = true;
2862
- _MemoryTransport._connections.delete(this._remoteInstanceId);
2863
- this._options.stream.unpipe(this._incomingDelay);
2864
- this._incomingDelay.unpipe(this._remoteConnection._options.stream);
2865
- this._remoteConnection._options.stream.unpipe(this._outgoingDelay);
2866
- this._outgoingDelay.unpipe(this._options.stream);
2867
- this._options.stream.unpipe(this._outgoingDelay);
2868
- this._remoteConnection.closed.emit();
2869
- this._remoteConnection._remoteConnection = void 0;
2870
- this._remoteConnection = void 0;
2871
- }
2872
- this.closed.emit();
2873
- log11("closed", void 0, {
2874
- F: __dxlog_file12,
2875
- L: 158,
2876
- S: this,
2877
- C: (f, a) => f(...a)
2878
- });
2879
- return this;
2880
- }
2881
- async onSignal({ payload }) {
2882
- log11("received signal", {
2883
- payload
2884
- }, {
2885
- F: __dxlog_file12,
2886
- L: 163,
2887
- S: this,
2888
- C: (f, a) => f(...a)
2889
- });
2890
- if (!payload?.transportId) {
2891
- return;
2892
- }
2893
- const transportId = payload.transportId;
2894
- if (transportId) {
2895
- const remoteId = PublicKey9.fromHex(transportId);
2896
- this._remote.wake(remoteId);
2897
- }
2898
- }
2899
- async getDetails() {
2900
- return this._instanceId.toHex();
2901
- }
2902
- async getStats() {
2903
- return {
2904
- bytesSent: 0,
2905
- bytesReceived: 0,
2906
- packetsSent: 0,
2907
- packetsReceived: 0
2908
- };
2909
- }
2910
- };
2911
- _ts_decorate5([
2912
- logInfo3
2913
- ], MemoryTransport.prototype, "_instanceId", void 0);
2914
- _ts_decorate5([
2915
- logInfo3
2916
- ], MemoryTransport.prototype, "_remoteInstanceId", void 0);
2917
- var toError = (err) => err instanceof Error ? err : new Error(String(err));
2918
-
2919
- // packages/core/mesh/network-manager/src/transport/transport.ts
2920
- var TransportKind;
2921
- (function(TransportKind2) {
2922
- TransportKind2["WEB_RTC"] = "WEB-RTC";
2923
- TransportKind2["WEB_RTC_PROXY"] = "WEB-RTC_PROXY";
2924
- TransportKind2["MEMORY"] = "MEMORY";
2925
- TransportKind2["TCP"] = "TCP";
2926
- })(TransportKind || (TransportKind = {}));
2927
-
2928
- // packages/core/mesh/network-manager/src/transport/webrtc/rtc-connection-factory.ts
2929
- import { Mutex } from "@dxos/async";
2930
- var BrowserRtcConnectionFactory = class {
2931
- async initialize() {
2932
- }
2933
- async onConnectionDestroyed() {
2934
- }
2935
- async createConnection(config) {
2936
- return new RTCPeerConnection(config);
2937
- }
2938
- async initConnection(connection, info) {
2939
- }
2940
- };
2941
- var NodeRtcConnectionFactory = class _NodeRtcConnectionFactory {
2942
- static {
2943
- this._createdConnections = 0;
2944
- }
2945
- static {
2946
- this._cleanupMutex = new Mutex();
2947
- }
2948
- // This should be inside the function to avoid triggering `eval` in the global scope.
2949
- // eslint-disable-next-line no-new-func
2950
- // TODO(burdon): Do imports here?
2951
- async initialize() {
2952
- }
2953
- async onConnectionDestroyed() {
2954
- return _NodeRtcConnectionFactory._cleanupMutex.executeSynchronized(async () => {
2955
- if (--_NodeRtcConnectionFactory._createdConnections === 0) {
2956
- (await import("#node-datachannel")).cleanup();
2957
- }
2958
- });
2959
- }
2960
- async createConnection(config) {
2961
- return _NodeRtcConnectionFactory._cleanupMutex.executeSynchronized(async () => {
2962
- const { RTCPeerConnection: RTCPeerConnection1 } = await import("#node-datachannel/polyfill");
2963
- _NodeRtcConnectionFactory._createdConnections++;
2964
- return new RTCPeerConnection1(config);
2965
- });
2966
- }
2967
- async initConnection(connection, info) {
2968
- if (info.initiator) {
2969
- connection.onnegotiationneeded?.(null);
2970
- }
2971
- }
2972
- };
2973
- var getRtcConnectionFactory = () => {
2974
- return typeof globalThis.RTCPeerConnection === "undefined" ? new NodeRtcConnectionFactory() : new BrowserRtcConnectionFactory();
2975
- };
2976
-
2977
- // packages/core/mesh/network-manager/src/transport/webrtc/rtc-peer-connection.ts
2978
- import { synchronized as synchronized5, Trigger as Trigger3, Mutex as Mutex2 } from "@dxos/async";
2979
- import { invariant as invariant12 } from "@dxos/invariant";
2980
- import { log as log13, logInfo as logInfo4 } from "@dxos/log";
2981
- import { ConnectivityError as ConnectivityError3 } from "@dxos/protocols";
2982
- import { trace as trace4 } from "@dxos/tracing";
2983
-
2984
- // packages/core/mesh/network-manager/src/transport/webrtc/rtc-transport-channel.ts
2985
- import { Duplex } from "node:stream";
2986
- import { Event as AsyncEvent } from "@dxos/async";
2987
- import { Resource } from "@dxos/context";
2988
- import { ErrorStream as ErrorStream4 } from "@dxos/debug";
2989
- import { invariant as invariant11 } from "@dxos/invariant";
2990
- import { log as log12 } from "@dxos/log";
2991
- import { ConnectivityError as ConnectivityError2 } from "@dxos/protocols";
2992
-
2993
- // packages/core/mesh/network-manager/src/transport/webrtc/rtc-transport-stats.ts
2994
- var describeSelectedRemoteCandidate = async (connection) => {
2995
- const stats = connection && await getRtcConnectionStats(connection);
2996
- const rc = stats?.remoteCandidate;
2997
- if (!rc) {
2998
- return "unavailable";
2999
- }
3000
- if (rc.candidateType === "relay") {
3001
- return `${rc.ip}:${rc.port} relay for ${rc.relatedAddress}:${rc.relatedPort}`;
3002
- }
3003
- return `${rc.ip}:${rc.port} ${rc.candidateType}`;
3004
- };
3005
- var createRtcTransportStats = async (connection, topic) => {
3006
- const stats = connection && await getRtcConnectionStats(connection, topic);
3007
- if (!stats) {
3008
- return {
3009
- bytesSent: 0,
3010
- bytesReceived: 0,
3011
- packetsSent: 0,
3012
- packetsReceived: 0,
3013
- rawStats: {}
3014
- };
3015
- }
3016
- return {
3017
- bytesSent: stats.dataChannel?.bytesSent,
3018
- bytesReceived: stats.dataChannel?.bytesReceived,
3019
- packetsSent: 0,
3020
- packetsReceived: 0,
3021
- rawStats: stats.raw
3022
- };
3023
- };
3024
- var getRtcConnectionStats = async (connection, channelTopic) => {
3025
- const stats = await connection.getStats();
3026
- const statsEntries = Array.from(stats.entries());
3027
- const transport = statsEntries.find(([_, entry]) => entry.type === "transport")?.[1];
3028
- const selectedCandidatePair = transport && statsEntries.find(([entryId]) => entryId === transport.selectedCandidatePairId)?.[1];
3029
- const remoteCandidate = selectedCandidatePair && statsEntries.find(([entryId]) => entryId === selectedCandidatePair.remoteCandidateId)?.[1];
3030
- const dataChannel = channelTopic && statsEntries.find(([_, entry]) => entry.type === "data-channel" && entry.label === channelTopic)?.[1];
3031
- return {
3032
- transport,
3033
- selectedCandidatePair,
3034
- dataChannel,
3035
- remoteCandidate,
3036
- raw: Object.fromEntries(stats)
3037
- };
3038
- };
3039
-
3040
- // packages/core/mesh/network-manager/src/transport/webrtc/rtc-transport-channel.ts
3041
- var __dxlog_file13 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/transport/webrtc/rtc-transport-channel.ts";
3042
- var MAX_MESSAGE_SIZE = 64 * 1024;
3043
- var MAX_BUFFERED_AMOUNT = 64 * 1024;
3044
- var RtcTransportChannel = class extends Resource {
3045
- constructor(_connection, _options) {
3046
- super();
3047
- this._connection = _connection;
3048
- this._options = _options;
3049
- this.closed = new AsyncEvent();
3050
- this.connected = new AsyncEvent();
3051
- this.errors = new ErrorStream4();
3052
- this._streamDataFlushedCallback = null;
3053
- this._isChannelCreationInProgress = false;
3054
- }
3055
- get isRtcChannelCreationInProgress() {
3056
- return this._isChannelCreationInProgress;
3057
- }
3058
- onConnectionError(error) {
3059
- if (this.isOpen) {
3060
- this.errors.raise(error);
3061
- }
3062
- }
3063
- async _open() {
3064
- invariant11(!this._isChannelCreationInProgress, void 0, {
3065
- F: __dxlog_file13,
3066
- L: 56,
3067
- S: this,
3068
- A: [
3069
- "!this._isChannelCreationInProgress",
3070
- ""
3071
- ]
3072
- });
3073
- this._isChannelCreationInProgress = true;
3074
- this._connection.createDataChannel(this._options.topic).then((channel) => {
3075
- if (this.isOpen) {
3076
- this._channel = channel;
3077
- this._initChannel(this._channel);
3078
- } else {
3079
- this._safeCloseChannel(channel);
3080
- }
3081
- }).catch((err) => {
3082
- if (this.isOpen) {
3083
- this.errors.raise(new ConnectivityError2(`Failed to create a channel: ${err?.message ?? "unknown reason."}`));
3084
- }
3085
- }).finally(() => {
3086
- this._isChannelCreationInProgress = false;
3087
- });
3088
- }
3089
- async _close() {
3090
- if (this._channel) {
3091
- this._safeCloseChannel(this._channel);
3092
- this._channel = void 0;
3093
- this._stream = void 0;
3094
- }
3095
- this.closed.emit();
3096
- log12("closed", void 0, {
3097
- F: __dxlog_file13,
3098
- L: 86,
3099
- S: this,
3100
- C: (f, a) => f(...a)
3101
- });
3102
- }
3103
- _initChannel(channel) {
3104
- Object.assign(channel, {
3105
- onopen: () => {
3106
- if (!this.isOpen) {
3107
- log12.warn("channel opened in a closed transport", {
3108
- topic: this._options.topic
3109
- }, {
3110
- F: __dxlog_file13,
3111
- L: 93,
3112
- S: this,
3113
- C: (f, a) => f(...a)
3114
- });
3115
- this._safeCloseChannel(channel);
3116
- return;
3117
- }
3118
- log12("onopen", void 0, {
3119
- F: __dxlog_file13,
3120
- L: 98,
3121
- S: this,
3122
- C: (f, a) => f(...a)
3123
- });
3124
- const duplex = new Duplex({
3125
- read: () => {
3126
- },
3127
- write: (chunk, encoding, callback) => {
3128
- return this._handleChannelWrite(chunk, callback);
3129
- }
3130
- });
3131
- duplex.pipe(this._options.stream).pipe(duplex);
3132
- this._stream = duplex;
3133
- this.connected.emit();
3134
- },
3135
- onclose: async () => {
3136
- log12("onclose", void 0, {
3137
- F: __dxlog_file13,
3138
- L: 111,
3139
- S: this,
3140
- C: (f, a) => f(...a)
3141
- });
3142
- await this.close();
3143
- },
3144
- onmessage: (event) => {
3145
- if (!this._stream) {
3146
- log12.warn("ignoring message on a closed channel", void 0, {
3147
- F: __dxlog_file13,
3148
- L: 117,
3149
- S: this,
3150
- C: (f, a) => f(...a)
3151
- });
3152
- return;
3153
- }
3154
- let data = event.data;
3155
- if (data instanceof ArrayBuffer) {
3156
- data = Buffer.from(data);
3157
- }
3158
- this._stream.push(data);
3159
- },
3160
- onerror: (event) => {
3161
- if (this.isOpen) {
3162
- const err = event.error instanceof Error ? event.error : new Error(`Datachannel error: ${event.type}.`);
3163
- this.errors.raise(err);
3164
- }
3165
- },
3166
- onbufferedamountlow: () => {
3167
- const cb = this._streamDataFlushedCallback;
3168
- this._streamDataFlushedCallback = null;
3169
- cb?.();
3170
- }
3171
- });
3172
- }
3173
- async _handleChannelWrite(chunk, callback) {
3174
- if (!this._channel) {
3175
- log12.warn("writing to a channel after a connection was closed", void 0, {
3176
- F: __dxlog_file13,
3177
- L: 145,
3178
- S: this,
3179
- C: (f, a) => f(...a)
3180
- });
3181
- return;
3182
- }
3183
- if (chunk.length > MAX_MESSAGE_SIZE) {
3184
- const error = new Error(`Message too large: ${chunk.length} > ${MAX_MESSAGE_SIZE}.`);
3185
- this.errors.raise(error);
3186
- callback();
3187
- return;
3188
- }
3189
- try {
3190
- this._channel.send(chunk);
3191
- } catch (err) {
3192
- this.errors.raise(err);
3193
- callback();
3194
- return;
3195
- }
3196
- if (this._channel.bufferedAmount > MAX_BUFFERED_AMOUNT) {
3197
- if (this._streamDataFlushedCallback !== null) {
3198
- log12.error("consumer trying to write before we are ready for more data", void 0, {
3199
- F: __dxlog_file13,
3200
- L: 166,
3201
- S: this,
3202
- C: (f, a) => f(...a)
3203
- });
3204
- }
3205
- this._streamDataFlushedCallback = callback;
3206
- } else {
3207
- callback();
3208
- }
3209
- }
3210
- _safeCloseChannel(channel) {
3211
- try {
3212
- channel.close();
3213
- } catch (error) {
3214
- log12.catch(error, void 0, {
3215
- F: __dxlog_file13,
3216
- L: 178,
3217
- S: this,
3218
- C: (f, a) => f(...a)
3219
- });
3220
- }
3221
- }
3222
- onSignal(signal) {
3223
- return this._connection.onSignal(signal);
3224
- }
3225
- async getDetails() {
3226
- return describeSelectedRemoteCandidate(this._connection.currentConnection);
3227
- }
3228
- async getStats() {
3229
- return createRtcTransportStats(this._connection.currentConnection, this._options.topic);
3230
- }
3231
- };
3232
-
3233
- // packages/core/mesh/network-manager/src/transport/webrtc/utils.ts
3234
- var chooseInitiatorPeer = (peer1Key, peer2Key) => peer1Key < peer2Key ? peer1Key : peer2Key;
3235
- var areSdpEqual = (sdp1, sdp2) => {
3236
- const sdp1Lines = deduplicatedSdpLines(sdp1);
3237
- const sdp2Lines = deduplicatedSdpLines(sdp2);
3238
- if (sdp1Lines.length !== sdp2Lines.length) {
3239
- return false;
3240
- }
3241
- return sdp1Lines.every((line, idx) => line === sdp2Lines[idx]);
3242
- };
3243
- var deduplicatedSdpLines = (sdp) => {
3244
- const deduplicatedLines = [];
3245
- const seenLines = [];
3246
- for (const line of sdp.split("\r\n")) {
3247
- if (line.startsWith("m")) {
3248
- seenLines.length = 0;
3249
- }
3250
- if (seenLines.includes(line)) {
3251
- continue;
3252
- }
3253
- seenLines.push(line);
3254
- deduplicatedLines.push(line);
3255
- }
3256
- return deduplicatedLines;
3257
- };
3258
-
3259
- // packages/core/mesh/network-manager/src/transport/webrtc/rtc-peer-connection.ts
3260
- function _ts_decorate6(decorators, target, key, desc) {
3261
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3262
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
3263
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
3264
- return c > 3 && r && Object.defineProperty(target, key, r), r;
3265
- }
3266
- var __dxlog_file14 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/transport/webrtc/rtc-peer-connection.ts";
3267
- var RtcPeerConnection = class {
3268
- constructor(_factory, _options) {
3269
- this._factory = _factory;
3270
- this._options = _options;
3271
- this._channelCreatedCallbacks = /* @__PURE__ */ new Map();
3272
- this._transportChannels = /* @__PURE__ */ new Map();
3273
- this._dataChannels = /* @__PURE__ */ new Map();
3274
- this._readyForCandidates = new Trigger3();
3275
- this._offerProcessingMutex = new Mutex2();
3276
- this._initiator = chooseInitiatorPeer(_options.ownPeerKey, _options.remotePeerKey) === _options.ownPeerKey;
3277
- }
3278
- get transportChannelCount() {
3279
- return this._transportChannels.size;
3280
- }
3281
- get currentConnection() {
3282
- return this._connection;
3283
- }
3284
- async createDataChannel(topic) {
3285
- const connection = await this._openConnection();
3286
- if (!this._transportChannels.has(topic)) {
3287
- if (!this._transportChannels.size) {
3288
- this._lockAndCloseConnection();
3289
- }
3290
- throw new Error("Transport closed while connection was being open");
3291
- }
3292
- if (this._initiator) {
3293
- const channel = connection.createDataChannel(topic);
3294
- this._dataChannels.set(topic, channel);
3295
- return channel;
3296
- } else {
3297
- const existingChannel = this._dataChannels.get(topic);
3298
- if (existingChannel) {
3299
- return existingChannel;
3300
- }
3301
- log13("waiting for initiator-peer to open a data channel", void 0, {
3302
- F: __dxlog_file14,
3303
- L: 90,
3304
- S: this,
3305
- C: (f, a) => f(...a)
3306
- });
3307
- return new Promise((resolve, reject) => {
3308
- this._channelCreatedCallbacks.set(topic, {
3309
- resolve,
3310
- reject
3311
- });
3312
- });
3313
- }
3314
- }
3315
- createTransportChannel(options) {
3316
- const channel = new RtcTransportChannel(this, options);
3317
- this._transportChannels.set(options.topic, channel);
3318
- channel.closed.on(() => {
3319
- this._transportChannels.delete(options.topic);
3320
- if (this._transportChannels.size === 0) {
3321
- this._lockAndCloseConnection();
3322
- }
3323
- });
3324
- return channel;
3325
- }
3326
- async _openConnection() {
3327
- if (this._connection) {
3328
- return this._connection;
3329
- }
3330
- log13("initializing connection...", () => ({
3331
- remotePeer: this._options.remotePeerKey
3332
- }), {
3333
- F: __dxlog_file14,
3334
- L: 115,
3335
- S: this,
3336
- C: (f, a) => f(...a)
3337
- });
3338
- const config = await this._loadConnectionConfig();
3339
- const connection = await this._factory.createConnection(config);
3340
- const iceCandidateErrors = [];
3341
- Object.assign(connection, {
3342
- onnegotiationneeded: async () => {
3343
- invariant12(this._initiator, void 0, {
3344
- F: __dxlog_file14,
3345
- L: 130,
3346
- S: this,
3347
- A: [
3348
- "this._initiator",
3349
- ""
3350
- ]
3351
- });
3352
- if (connection !== this._connection) {
3353
- this._onConnectionCallbackAfterClose("onnegotiationneeded", connection);
3354
- return;
3355
- }
3356
- log13("onnegotiationneeded", void 0, {
3357
- F: __dxlog_file14,
3358
- L: 137,
3359
- S: this,
3360
- C: (f, a) => f(...a)
3361
- });
3362
- try {
3363
- const offer = await connection.createOffer();
3364
- await connection.setLocalDescription(offer);
3365
- await this._sendDescription(connection, offer);
3366
- } catch (err) {
3367
- this._lockAndAbort(connection, err);
3368
- }
3369
- },
3370
- // When ICE candidate identified (should be sent to remote peer) and when ICE gathering finalized.
3371
- // https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/icecandidate_event
3372
- onicecandidate: async (event) => {
3373
- if (connection !== this._connection) {
3374
- this._onConnectionCallbackAfterClose("onicecandidate", connection);
3375
- return;
3376
- }
3377
- if (event.candidate) {
3378
- log13("onicecandidate", {
3379
- candidate: event.candidate.candidate
3380
- }, {
3381
- F: __dxlog_file14,
3382
- L: 156,
3383
- S: this,
3384
- C: (f, a) => f(...a)
3385
- });
3386
- await this._sendIceCandidate(event.candidate);
3387
- } else {
3388
- log13("onicecandidate gathering complete", void 0, {
3389
- F: __dxlog_file14,
3390
- L: 159,
3391
- S: this,
3392
- C: (f, a) => f(...a)
3393
- });
3394
- }
3395
- },
3396
- // When error occurs while performing ICE negotiations through a STUN or TURN server.
3397
- // It's ok for some candidates to fail if a working pair is eventually found.
3398
- // https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/icecandidateerror_event
3399
- onicecandidateerror: (event) => {
3400
- const { url, errorCode, errorText } = event;
3401
- iceCandidateErrors.push({
3402
- url,
3403
- errorCode,
3404
- errorText
3405
- });
3406
- },
3407
- // When possible error during ICE gathering.
3408
- // https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/iceconnectionstatechange_event
3409
- oniceconnectionstatechange: () => {
3410
- if (connection !== this._connection) {
3411
- this._onConnectionCallbackAfterClose("oniceconnectionstatechange", connection);
3412
- return;
3413
- }
3414
- log13("oniceconnectionstatechange", {
3415
- state: connection.iceConnectionState
3416
- }, {
3417
- F: __dxlog_file14,
3418
- L: 179,
3419
- S: this,
3420
- C: (f, a) => f(...a)
3421
- });
3422
- if (connection.iceConnectionState === "failed") {
3423
- this._lockAndAbort(connection, createIceFailureError(iceCandidateErrors));
3424
- }
3425
- },
3426
- // When new track (or channel) is added.
3427
- // State: { new, connecting, connected, disconnected, failed, closed }
3428
- // https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/connectionstatechange_event
3429
- onconnectionstatechange: () => {
3430
- if (connection !== this._connection) {
3431
- if (connection.connectionState !== "closed" && connection.connectionState !== "failed") {
3432
- this._onConnectionCallbackAfterClose("onconnectionstatechange", connection);
3433
- }
3434
- return;
3435
- }
3436
- log13("onconnectionstatechange", {
3437
- state: connection.connectionState
3438
- }, {
3439
- F: __dxlog_file14,
3440
- L: 196,
3441
- S: this,
3442
- C: (f, a) => f(...a)
3443
- });
3444
- if (connection.connectionState === "failed") {
3445
- this._lockAndAbort(connection, new Error("Connection failed."));
3446
- }
3447
- },
3448
- onsignalingstatechange: () => {
3449
- log13("onsignalingstatechange", {
3450
- state: connection.signalingState
3451
- }, {
3452
- F: __dxlog_file14,
3453
- L: 203,
3454
- S: this,
3455
- C: (f, a) => f(...a)
3456
- });
3457
- },
3458
- // When channel is added to connection.
3459
- // https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/datachannel_event
3460
- ondatachannel: (event) => {
3461
- invariant12(!this._initiator, "Initiator is expected to create data channels.", {
3462
- F: __dxlog_file14,
3463
- L: 209,
3464
- S: this,
3465
- A: [
3466
- "!this._initiator",
3467
- "'Initiator is expected to create data channels.'"
3468
- ]
3469
- });
3470
- if (connection !== this._connection) {
3471
- this._onConnectionCallbackAfterClose("ondatachannel", connection);
3472
- return;
3473
- }
3474
- log13("ondatachannel", {
3475
- label: event.channel.label
3476
- }, {
3477
- F: __dxlog_file14,
3478
- L: 216,
3479
- S: this,
3480
- C: (f, a) => f(...a)
3481
- });
3482
- this._dataChannels.set(event.channel.label, event.channel);
3483
- const pendingCallback = this._channelCreatedCallbacks.get(event.channel.label);
3484
- if (pendingCallback) {
3485
- this._channelCreatedCallbacks.delete(event.channel.label);
3486
- pendingCallback.resolve(event.channel);
3487
- }
3488
- }
3489
- });
3490
- this._connection = connection;
3491
- this._readyForCandidates.reset();
3492
- await this._factory.initConnection(connection, {
3493
- initiator: this._initiator
3494
- });
3495
- return this._connection;
3496
- }
3497
- _lockAndAbort(connection, error) {
3498
- this._abortConnection(connection, error);
3499
- }
3500
- _abortConnection(connection, error) {
3501
- if (connection !== this._connection) {
3502
- log13.error("attempted to abort an inactive connection", {
3503
- error
3504
- }, {
3505
- F: __dxlog_file14,
3506
- L: 241,
3507
- S: this,
3508
- C: (f, a) => f(...a)
3509
- });
3510
- this._safeCloseConnection(connection);
3511
- return;
3512
- }
3513
- for (const [topic, pendingCallback] of this._channelCreatedCallbacks.entries()) {
3514
- pendingCallback.reject(error);
3515
- this._transportChannels.delete(topic);
3516
- }
3517
- this._channelCreatedCallbacks.clear();
3518
- for (const channel of this._transportChannels.values()) {
3519
- channel.onConnectionError(error);
3520
- }
3521
- this._transportChannels.clear();
3522
- this._safeCloseConnection();
3523
- log13("connection aborted", {
3524
- reason: error.message
3525
- }, {
3526
- F: __dxlog_file14,
3527
- L: 255,
3528
- S: this,
3529
- C: (f, a) => f(...a)
3530
- });
3531
- }
3532
- _lockAndCloseConnection() {
3533
- invariant12(this._transportChannels.size === 0, void 0, {
3534
- F: __dxlog_file14,
3535
- L: 260,
3536
- S: this,
3537
- A: [
3538
- "this._transportChannels.size === 0",
3539
- ""
3540
- ]
3541
- });
3542
- if (this._connection) {
3543
- this._safeCloseConnection();
3544
- log13("connection closed", void 0, {
3545
- F: __dxlog_file14,
3546
- L: 263,
3547
- S: this,
3548
- C: (f, a) => f(...a)
3549
- });
3550
- }
3551
- }
3552
- async onSignal(signal) {
3553
- const connection = this._connection;
3554
- if (!connection) {
3555
- log13.warn("a signal ignored because the connection was closed", {
3556
- type: signal.payload.data.type
3557
- }, {
3558
- F: __dxlog_file14,
3559
- L: 271,
3560
- S: this,
3561
- C: (f, a) => f(...a)
3562
- });
3563
- return;
3564
- }
3565
- const data = signal.payload.data;
3566
- switch (data.type) {
3567
- case "offer": {
3568
- await this._offerProcessingMutex.executeSynchronized(async () => {
3569
- if (isRemoteDescriptionSet(connection, data)) {
3570
- return;
3571
- }
3572
- if (connection.connectionState !== "new") {
3573
- this._abortConnection(connection, new Error(`Received an offer in ${connection.connectionState}.`));
3574
- return;
3575
- }
3576
- try {
3577
- await connection.setRemoteDescription({
3578
- type: data.type,
3579
- sdp: data.sdp
3580
- });
3581
- const answer = await connection.createAnswer();
3582
- await connection.setLocalDescription(answer);
3583
- await this._sendDescription(connection, answer);
3584
- this._onSessionNegotiated(connection);
3585
- } catch (err) {
3586
- this._abortConnection(connection, new Error("Error handling a remote offer.", {
3587
- cause: err
3588
- }));
3589
- }
3590
- });
3591
- break;
3592
- }
3593
- case "answer":
3594
- await this._offerProcessingMutex.executeSynchronized(async () => {
3595
- try {
3596
- if (isRemoteDescriptionSet(connection, data)) {
3597
- return;
3598
- }
3599
- if (connection.signalingState !== "have-local-offer") {
3600
- this._abortConnection(connection, new Error(`Unexpected answer from remote peer, signalingState was ${connection.signalingState}.`));
3601
- return;
3602
- }
3603
- await connection.setRemoteDescription({
3604
- type: data.type,
3605
- sdp: data.sdp
3606
- });
3607
- this._onSessionNegotiated(connection);
3608
- } catch (err) {
3609
- this._abortConnection(connection, new Error("Error handling a remote answer.", {
3610
- cause: err
3611
- }));
3612
- }
3613
- });
3614
- break;
3615
- case "candidate":
3616
- void this._processIceCandidate(connection, data.candidate);
3617
- break;
3618
- default:
3619
- this._abortConnection(connection, new Error(`Unknown signal type ${data.type}.`));
3620
- break;
3621
- }
3622
- log13("signal processed", void 0, {
3623
- F: __dxlog_file14,
3624
- L: 330,
3625
- S: this,
3626
- C: (f, a) => f(...a)
3627
- });
3628
- }
3629
- async _processIceCandidate(connection, candidate) {
3630
- try {
3631
- await this._readyForCandidates.wait();
3632
- if (connection === this._connection) {
3633
- log13("adding ice candidate", {
3634
- candidate
3635
- }, {
3636
- F: __dxlog_file14,
3637
- L: 338,
3638
- S: this,
3639
- C: (f, a) => f(...a)
3640
- });
3641
- await connection.addIceCandidate(candidate);
3642
- }
3643
- } catch (err) {
3644
- log13.catch(err, void 0, {
3645
- F: __dxlog_file14,
3646
- L: 342,
3647
- S: this,
3648
- C: (f, a) => f(...a)
3649
- });
3650
- }
3651
- }
3652
- _onSessionNegotiated(connection) {
3653
- if (connection === this._connection) {
3654
- log13("ready to process ice candidates", void 0, {
3655
- F: __dxlog_file14,
3656
- L: 348,
3657
- S: this,
3658
- C: (f, a) => f(...a)
3659
- });
3660
- this._readyForCandidates.wake();
3661
- } else {
3662
- log13.warn("session was negotiated after connection became inactive", void 0, {
3663
- F: __dxlog_file14,
3664
- L: 351,
3665
- S: this,
3666
- C: (f, a) => f(...a)
3667
- });
3668
- }
3669
- }
3670
- _onConnectionCallbackAfterClose(callback, connection) {
3671
- log13.warn("callback invoked after a connection was destroyed, this is probably a bug", {
3672
- callback,
3673
- state: connection.connectionState
3674
- }, {
3675
- F: __dxlog_file14,
3676
- L: 356,
3677
- S: this,
3678
- C: (f, a) => f(...a)
3679
- });
3680
- this._safeCloseConnection(connection);
3681
- }
3682
- _safeCloseConnection(connection = this._connection) {
3683
- const resetFields = this._connection && connection === this._connection;
3684
- try {
3685
- connection?.close();
3686
- } catch (err) {
3687
- log13.catch(err, void 0, {
3688
- F: __dxlog_file14,
3689
- L: 368,
3690
- S: this,
3691
- C: (f, a) => f(...a)
3692
- });
3693
- }
3694
- if (resetFields) {
3695
- this._connection = void 0;
3696
- this._dataChannels.clear();
3697
- this._readyForCandidates.wake();
3698
- void this._factory.onConnectionDestroyed().catch((err) => log13.catch(err, void 0, {
3699
- F: __dxlog_file14,
3700
- L: 374,
3701
- S: this,
3702
- C: (f, a) => f(...a)
3703
- }));
3704
- for (const [_, pendingCallback] of this._channelCreatedCallbacks.entries()) {
3705
- pendingCallback.reject("Connection closed.");
3706
- }
3707
- this._channelCreatedCallbacks.clear();
3708
- }
3709
- }
3710
- async _loadConnectionConfig() {
3711
- const config = {
3712
- ...this._options.webrtcConfig
3713
- };
3714
- try {
3715
- const providedIceServers = await this._options.iceProvider?.getIceServers() ?? [];
3716
- if (providedIceServers.length > 0) {
3717
- config.iceServers = [
3718
- ...config.iceServers ?? [],
3719
- ...providedIceServers
3720
- ];
3721
- }
3722
- } catch (error) {
3723
- log13.catch(error, void 0, {
3724
- F: __dxlog_file14,
3725
- L: 390,
3726
- S: this,
3727
- C: (f, a) => f(...a)
3728
- });
3729
- }
3730
- return config;
3731
- }
3732
- async _sendIceCandidate(candidate) {
3733
- try {
3734
- await this._options.sendSignal({
3735
- payload: {
3736
- data: {
3737
- type: "candidate",
3738
- candidate: {
3739
- candidate: candidate.candidate,
3740
- // These fields never seem to be not null, but connecting to Chrome doesn't work if they are.
3741
- sdpMLineIndex: candidate.sdpMLineIndex ?? "0",
3742
- sdpMid: candidate.sdpMid ?? "0"
3743
- }
3744
- }
3745
- }
3746
- });
3747
- } catch (err) {
3748
- log13.warn("signaling error", {
3749
- err
3750
- }, {
3751
- F: __dxlog_file14,
3752
- L: 411,
3753
- S: this,
3754
- C: (f, a) => f(...a)
3755
- });
3756
- }
3757
- }
3758
- async _sendDescription(connection, description) {
3759
- if (connection !== this._connection) {
3760
- return;
3761
- }
3762
- const data = {
3763
- type: description.type,
3764
- sdp: description.sdp
3765
- };
3766
- await this._options.sendSignal({
3767
- payload: {
3768
- data
3769
- }
3770
- });
3771
- }
3772
- get _connectionInfo() {
3773
- const connectionInfo = this._connection && {
3774
- connectionState: this._connection.connectionState,
3775
- iceConnectionState: this._connection.iceConnectionState,
3776
- iceGatheringState: this._connection.iceGatheringState,
3777
- signalingState: this._connection.signalingState,
3778
- remoteDescription: this._connection.remoteDescription,
3779
- localDescription: this._connection.localDescription
3780
- };
3781
- return {
3782
- ...connectionInfo,
3783
- ts: Date.now(),
3784
- remotePeerKey: this._options.remotePeerKey,
3785
- channels: [
3786
- ...this._transportChannels.keys()
3787
- ].map((topic) => topic),
3788
- config: this._connection?.getConfiguration()
3789
- };
3790
- }
3791
- get _loggerContext() {
3792
- return {
3793
- ownPeerKey: this._options.ownPeerKey,
3794
- remotePeerKey: this._options.remotePeerKey,
3795
- initiator: this._initiator,
3796
- channels: this._transportChannels.size
3797
- };
3798
- }
3799
- };
3800
- _ts_decorate6([
3801
- synchronized5
3802
- ], RtcPeerConnection.prototype, "_openConnection", null);
3803
- _ts_decorate6([
3804
- synchronized5
3805
- ], RtcPeerConnection.prototype, "_lockAndAbort", null);
3806
- _ts_decorate6([
3807
- synchronized5
3808
- ], RtcPeerConnection.prototype, "_lockAndCloseConnection", null);
3809
- _ts_decorate6([
3810
- synchronized5
3811
- ], RtcPeerConnection.prototype, "onSignal", null);
3812
- _ts_decorate6([
3813
- trace4.info()
3814
- ], RtcPeerConnection.prototype, "_connectionInfo", null);
3815
- _ts_decorate6([
3816
- logInfo4
3817
- ], RtcPeerConnection.prototype, "_loggerContext", null);
3818
- RtcPeerConnection = _ts_decorate6([
3819
- trace4.resource()
3820
- ], RtcPeerConnection);
3821
- var isRemoteDescriptionSet = (connection, data) => {
3822
- if (!connection.remoteDescription?.type || connection.remoteDescription?.type !== data.type) {
3823
- return false;
3824
- }
3825
- return areSdpEqual(connection.remoteDescription.sdp, data.sdp);
3826
- };
3827
- var createIceFailureError = (details) => {
3828
- const candidateErrors = details.map(({ url, errorCode, errorText }) => `${errorCode} ${url}: ${errorText}`);
3829
- return new ConnectivityError3(`ICE failed:
3830
- ${candidateErrors.join("\n")}`);
3831
- };
3832
-
3833
- // packages/core/mesh/network-manager/src/transport/webrtc/rtc-transport-factory.ts
3834
- var createRtcTransportFactory = (webrtcConfig, iceProvider) => {
3835
- const connectionFactory = getRtcConnectionFactory();
3836
- return {
3837
- createTransport: (options) => {
3838
- const connection = new RtcPeerConnection(connectionFactory, {
3839
- ownPeerKey: options.ownPeerKey,
3840
- remotePeerKey: options.remotePeerKey,
3841
- sendSignal: options.sendSignal,
3842
- webrtcConfig,
3843
- iceProvider
3844
- });
3845
- return connection.createTransportChannel(options);
3846
- }
3847
- };
3848
- };
3849
-
3850
- // packages/core/mesh/network-manager/src/transport/webrtc/rtc-transport-proxy.ts
3851
- import { Writable } from "node:stream";
3852
- import { Event as Event8, scheduleTask as scheduleTask4 } from "@dxos/async";
3853
- import { Resource as Resource2 } from "@dxos/context";
3854
- import { ErrorStream as ErrorStream5 } from "@dxos/debug";
3855
- import { invariant as invariant13 } from "@dxos/invariant";
3856
- import { PublicKey as PublicKey10 } from "@dxos/keys";
3857
- import { log as log14 } from "@dxos/log";
3858
- import { ConnectionResetError as ConnectionResetError2, ConnectivityError as ConnectivityError4, TimeoutError as TimeoutError3 } from "@dxos/protocols";
3859
- import { ConnectionState as ConnectionState3 } from "@dxos/protocols/proto/dxos/mesh/bridge";
3860
- import { arrayToBuffer } from "@dxos/util";
3861
- var __dxlog_file15 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/transport/webrtc/rtc-transport-proxy.ts";
3862
- var RPC_TIMEOUT = 1e4;
3863
- var CLOSE_RPC_TIMEOUT = 3e3;
3864
- var RESP_MIN_THRESHOLD = 500;
3865
- var RtcTransportProxy = class extends Resource2 {
3866
- constructor(_options) {
3867
- super();
3868
- this._options = _options;
3869
- this._proxyId = PublicKey10.random();
3870
- this.closed = new Event8();
3871
- this.connected = new Event8();
3872
- this.errors = new ErrorStream5();
3873
- }
3874
- async _open() {
3875
- let stream;
3876
- try {
3877
- stream = this._options.bridgeService.open({
3878
- proxyId: this._proxyId,
3879
- remotePeerKey: this._options.remotePeerKey,
3880
- ownPeerKey: this._options.ownPeerKey,
3881
- topic: this._options.topic,
3882
- initiator: this._options.initiator ?? false
3883
- }, {
3884
- timeout: RPC_TIMEOUT
3885
- });
3886
- } catch (error) {
3887
- this.errors.raise(error);
3888
- return;
3889
- }
3890
- this._serviceStream = stream;
3891
- stream.waitUntilReady().then(() => {
3892
- stream.subscribe(async (event) => {
3893
- log14("rtc transport proxy event", event, {
3894
- F: __dxlog_file15,
3895
- L: 66,
3896
- S: this,
3897
- C: (f, a) => f(...a)
3898
- });
3899
- if (event.connection) {
3900
- await this._handleConnection(event.connection);
3901
- } else if (event.data) {
3902
- this._handleData(event.data);
3903
- } else if (event.signal) {
3904
- await this._handleSignal(event.signal);
3905
- }
3906
- }, (err) => {
3907
- log14("rtc bridge stream closed", {
3908
- err
3909
- }, {
3910
- F: __dxlog_file15,
3911
- L: 76,
3912
- S: this,
3913
- C: (f, a) => f(...a)
3914
- });
3915
- if (err) {
3916
- this._raiseIfOpen(err);
3917
- } else {
3918
- void this.close();
3919
- }
3920
- });
3921
- const connectorStream = new Writable({
3922
- write: (chunk, _, callback) => {
3923
- const sendStartMs = Date.now();
3924
- this._options.bridgeService.sendData({
3925
- proxyId: this._proxyId,
3926
- payload: chunk
3927
- }, {
3928
- timeout: RPC_TIMEOUT
3929
- }).then(() => {
3930
- if (Date.now() - sendStartMs > RESP_MIN_THRESHOLD) {
3931
- log14("slow response, delaying callback", void 0, {
3932
- F: __dxlog_file15,
3933
- L: 93,
3934
- S: this,
3935
- C: (f, a) => f(...a)
3936
- });
3937
- scheduleTask4(this._ctx, () => callback(), RESP_MIN_THRESHOLD);
3938
- } else {
3939
- callback();
3940
- }
3941
- }, (err) => {
3942
- callback();
3943
- this._raiseIfOpen(err);
3944
- });
3945
- }
3946
- });
3947
- connectorStream.on("error", (err) => {
3948
- this._raiseIfOpen(err);
3949
- });
3950
- this._options.stream.pipe(connectorStream);
3951
- }, (error) => {
3952
- if (error) {
3953
- this._raiseIfOpen(error);
3954
- } else {
3955
- void this.close();
3956
- }
3957
- });
3958
- }
3959
- async _close() {
3960
- try {
3961
- await this._serviceStream?.close();
3962
- this._serviceStream = void 0;
3963
- } catch (err) {
3964
- log14.catch(err, void 0, {
3965
- F: __dxlog_file15,
3966
- L: 128,
3967
- S: this,
3968
- C: (f, a) => f(...a)
3969
- });
3970
- }
3971
- try {
3972
- await this._options.bridgeService.close({
3973
- proxyId: this._proxyId
3974
- }, {
3975
- timeout: CLOSE_RPC_TIMEOUT
3976
- });
3977
- } catch (err) {
3978
- log14.catch(err, void 0, {
3979
- F: __dxlog_file15,
3980
- L: 134,
3981
- S: this,
3982
- C: (f, a) => f(...a)
3983
- });
3984
- }
3985
- this.closed.emit();
3986
- }
3987
- async onSignal(signal) {
3988
- this._options.bridgeService.sendSignal({
3989
- proxyId: this._proxyId,
3990
- signal
3991
- }, {
3992
- timeout: RPC_TIMEOUT
3993
- }).catch((err) => this._raiseIfOpen(decodeError(err)));
3994
- }
3995
- async _handleConnection(connectionEvent) {
3996
- if (connectionEvent.error) {
3997
- this.errors.raise(decodeError(connectionEvent.error));
3998
- return;
3999
- }
4000
- switch (connectionEvent.state) {
4001
- case ConnectionState3.CONNECTED: {
4002
- this.connected.emit();
4003
- break;
4004
- }
4005
- case ConnectionState3.CLOSED: {
4006
- await this.close();
4007
- break;
4008
- }
4009
- }
4010
- }
4011
- _handleData(dataEvent) {
4012
- try {
4013
- this._options.stream.write(arrayToBuffer(dataEvent.payload));
4014
- } catch (error) {
4015
- this._raiseIfOpen(error);
4016
- }
4017
- }
4018
- async _handleSignal(signalEvent) {
4019
- try {
4020
- await this._options.sendSignal(signalEvent.payload);
4021
- } catch (error) {
4022
- const type = signalEvent.payload.payload.data?.type;
4023
- if (type === "offer" || type === "answer") {
4024
- this._raiseIfOpen(new ConnectivityError4(`Session establishment failed: ${type} couldn't be sent.`));
4025
- }
4026
- }
4027
- }
4028
- async getDetails() {
4029
- try {
4030
- const response = await this._options.bridgeService.getDetails({
4031
- proxyId: this._proxyId
4032
- }, {
4033
- timeout: RPC_TIMEOUT
4034
- });
4035
- return response.details;
4036
- } catch (err) {
4037
- return "bridge-svc unreachable";
4038
- }
4039
- }
4040
- async getStats() {
4041
- try {
4042
- const response = await this._options.bridgeService.getStats({
4043
- proxyId: this._proxyId
4044
- }, {
4045
- timeout: RPC_TIMEOUT
4046
- });
4047
- return response.stats;
4048
- } catch (err) {
4049
- return {
4050
- bytesSent: 0,
4051
- bytesReceived: 0,
4052
- packetsSent: 0,
4053
- packetsReceived: 0,
4054
- rawStats: "bridge-svc unreachable"
4055
- };
4056
- }
4057
- }
4058
- _raiseIfOpen(error) {
4059
- if (this.isOpen) {
4060
- this.errors.raise(error);
4061
- } else {
4062
- log14.info("error swallowed because transport was closed", {
4063
- message: error.message
4064
- }, {
4065
- F: __dxlog_file15,
4066
- L: 215,
4067
- S: this,
4068
- C: (f, a) => f(...a)
4069
- });
4070
- }
4071
- }
4072
- /**
4073
- * Called when underlying proxy service becomes unavailable.
4074
- */
4075
- forceClose() {
4076
- void this._serviceStream?.close();
4077
- this.closed.emit();
4078
- }
4079
- };
4080
- var RtcTransportProxyFactory = class {
4081
- constructor() {
4082
- this._connections = /* @__PURE__ */ new Set();
4083
- }
4084
- /**
4085
- * Sets the current BridgeService to be used to open connections.
4086
- * Calling this method will close any existing connections.
4087
- */
4088
- setBridgeService(bridgeService) {
4089
- this._bridgeService = bridgeService;
4090
- for (const connection of this._connections) {
4091
- connection.forceClose();
4092
- }
4093
- return this;
4094
- }
4095
- createTransport(options) {
4096
- invariant13(this._bridgeService, "RtcTransportProxyFactory is not ready to open connections", {
4097
- F: __dxlog_file15,
4098
- L: 245,
4099
- S: this,
4100
- A: [
4101
- "this._bridgeService",
4102
- "'RtcTransportProxyFactory is not ready to open connections'"
4103
- ]
4104
- });
4105
- const transport = new RtcTransportProxy({
4106
- ...options,
4107
- bridgeService: this._bridgeService
4108
- });
4109
- this._connections.add(transport);
4110
- transport.closed.on(() => this._connections.delete(transport));
4111
- return transport;
4112
- }
4113
- };
4114
- var decodeError = (err) => {
4115
- const message = typeof err === "string" ? err : err.message;
4116
- if (message.includes("CONNECTION_RESET")) {
4117
- return new ConnectionResetError2(message);
4118
- } else if (message.includes("TIMEOUT")) {
4119
- return new TimeoutError3(message);
4120
- } else if (message.includes("CONNECTIVITY_ERROR")) {
4121
- return new ConnectivityError4(message);
4122
- } else {
4123
- return typeof err === "string" ? new Error(err) : err;
4124
- }
4125
- };
4126
-
4127
- // packages/core/mesh/network-manager/src/transport/webrtc/rtc-transport-service.ts
4128
- import { Duplex as Duplex2 } from "node:stream";
4129
- import { Stream } from "@dxos/codec-protobuf";
4130
- import { invariant as invariant14 } from "@dxos/invariant";
4131
- import { PublicKey as PublicKey11 } from "@dxos/keys";
4132
- import { log as log15 } from "@dxos/log";
4133
- import { ConnectionState as ConnectionState4 } from "@dxos/protocols/proto/dxos/mesh/bridge";
4134
- import { ComplexMap as ComplexMap8 } from "@dxos/util";
4135
- var __dxlog_file16 = "/home/runner/work/dxos/dxos/packages/core/mesh/network-manager/src/transport/webrtc/rtc-transport-service.ts";
4136
- var RtcTransportService = class {
4137
- constructor(webrtcConfig, iceProvider, _transportFactory = createRtcTransportFactory(webrtcConfig, iceProvider)) {
4138
- this._transportFactory = _transportFactory;
4139
- this._openTransports = new ComplexMap8(PublicKey11.hash);
4140
- }
4141
- hasOpenTransports() {
4142
- return this._openTransports.size > 0;
4143
- }
4144
- open(request) {
4145
- const existingTransport = this._openTransports.get(request.proxyId);
4146
- if (existingTransport) {
4147
- log15.error("requesting a new transport bridge for an existing proxy", void 0, {
4148
- F: __dxlog_file16,
4149
- L: 53,
4150
- S: this,
4151
- C: (f, a) => f(...a)
4152
- });
4153
- void this._safeCloseTransport(existingTransport);
4154
- this._openTransports.delete(request.proxyId);
4155
- }
4156
- return new Stream(({ ready, next, close }) => {
4157
- const pushNewState = createStateUpdater(next);
4158
- const transportStream = new Duplex2({
4159
- read: () => {
4160
- const callbacks = [
4161
- ...transportState.writeProcessedCallbacks
4162
- ];
4163
- transportState.writeProcessedCallbacks.length = 0;
4164
- callbacks.forEach((cb) => cb());
4165
- },
4166
- write: function(chunk, _, callback) {
4167
- next({
4168
- data: {
4169
- payload: chunk
4170
- }
4171
- });
4172
- callback();
4173
- }
4174
- });
4175
- const transport = this._transportFactory.createTransport({
4176
- initiator: request.initiator,
4177
- topic: request.topic,
4178
- ownPeerKey: request.ownPeerKey,
4179
- remotePeerKey: request.remotePeerKey,
4180
- stream: transportStream,
4181
- sendSignal: async (signal) => {
4182
- next({
4183
- signal: {
4184
- payload: signal
4185
- }
4186
- });
4187
- }
4188
- });
4189
- const transportState = {
4190
- proxyId: request.proxyId,
4191
- transport,
4192
- connectorStream: transportStream,
4193
- writeProcessedCallbacks: []
4194
- };
4195
- pushNewState(ConnectionState4.CONNECTING);
4196
- transport.connected.on(() => pushNewState(ConnectionState4.CONNECTED));
4197
- transport.errors.handle(async (err) => {
4198
- pushNewState(ConnectionState4.CLOSED, err);
4199
- void this._safeCloseTransport(transportState);
4200
- close(err);
4201
- });
4202
- transport.closed.on(async () => {
4203
- pushNewState(ConnectionState4.CLOSED);
4204
- void this._safeCloseTransport(transportState);
4205
- close();
4206
- });
4207
- this._openTransports.set(request.proxyId, transportState);
4208
- transport.open().catch(async (err) => {
4209
- pushNewState(ConnectionState4.CLOSED, err);
4210
- void this._safeCloseTransport(transportState);
4211
- close(err);
4212
- });
4213
- ready();
4214
- });
4215
- }
4216
- async sendSignal({ proxyId, signal }) {
4217
- const transport = this._openTransports.get(proxyId);
4218
- invariant14(transport, void 0, {
4219
- F: __dxlog_file16,
4220
- L: 121,
4221
- S: this,
4222
- A: [
4223
- "transport",
4224
- ""
4225
- ]
4226
- });
4227
- await transport.transport.onSignal(signal);
4228
- }
4229
- async getDetails({ proxyId }) {
4230
- const transport = this._openTransports.get(proxyId);
4231
- invariant14(transport, void 0, {
4232
- F: __dxlog_file16,
4233
- L: 128,
4234
- S: this,
4235
- A: [
4236
- "transport",
4237
- ""
4238
- ]
4239
- });
4240
- return {
4241
- details: await transport.transport.getDetails()
4242
- };
4243
- }
4244
- async getStats({ proxyId }) {
4245
- const transport = this._openTransports.get(proxyId);
4246
- invariant14(transport, void 0, {
4247
- F: __dxlog_file16,
4248
- L: 135,
4249
- S: this,
4250
- A: [
4251
- "transport",
4252
- ""
4253
- ]
4254
- });
4255
- return {
4256
- stats: await transport.transport.getStats()
4257
- };
4258
- }
4259
- async sendData({ proxyId, payload }) {
4260
- const transport = this._openTransports.get(proxyId);
4261
- invariant14(transport, void 0, {
4262
- F: __dxlog_file16,
4263
- L: 142,
4264
- S: this,
4265
- A: [
4266
- "transport",
4267
- ""
4268
- ]
4269
- });
4270
- const bufferHasSpace = transport.connectorStream.push(payload);
4271
- if (!bufferHasSpace) {
4272
- await new Promise((resolve) => {
4273
- transport.writeProcessedCallbacks.push(resolve);
4274
- });
4275
- }
4276
- }
4277
- async close({ proxyId }) {
4278
- const transport = this._openTransports.get(proxyId);
4279
- if (!transport) {
4280
- return;
4281
- }
4282
- this._openTransports.delete(proxyId);
4283
- await this._safeCloseTransport(transport);
4284
- }
4285
- async _safeCloseTransport(transport) {
4286
- if (this._openTransports.get(transport.proxyId) === transport) {
4287
- this._openTransports.delete(transport.proxyId);
4288
- }
4289
- transport.writeProcessedCallbacks.forEach((cb) => cb());
4290
- try {
4291
- await transport.transport.close();
4292
- } catch (error) {
4293
- log15.warn("transport close error", {
4294
- message: error?.message
4295
- }, {
4296
- F: __dxlog_file16,
4297
- L: 172,
4298
- S: this,
4299
- C: (f, a) => f(...a)
4300
- });
4301
- }
4302
- try {
4303
- transport.connectorStream.end();
4304
- } catch (error) {
4305
- log15.warn("connectorStream close error", {
4306
- message: error?.message
4307
- }, {
4308
- F: __dxlog_file16,
4309
- L: 177,
4310
- S: this,
4311
- C: (f, a) => f(...a)
4312
- });
4313
- }
4314
- log15("closed", void 0, {
4315
- F: __dxlog_file16,
4316
- L: 179,
4317
- S: this,
4318
- C: (f, a) => f(...a)
4319
- });
4320
- }
4321
- };
4322
- var createStateUpdater = (next) => {
4323
- return (state, err) => {
4324
- next({
4325
- connection: {
4326
- state,
4327
- ...err ? {
4328
- error: err.message
4329
- } : void 0
4330
- }
4331
- });
4332
- };
4333
- };
4334
-
4335
- // packages/core/mesh/network-manager/src/wire-protocol.ts
4336
- import { Teleport } from "@dxos/teleport";
4337
- var createTeleportProtocolFactory = (onConnection, defaultParams) => {
4338
- return (params) => {
4339
- const teleport = new Teleport({
4340
- ...defaultParams,
4341
- ...params
4342
- });
4343
- return {
4344
- stream: teleport.stream,
4345
- open: async (sessionId) => {
4346
- await teleport.open(sessionId);
4347
- await onConnection(teleport);
4348
- },
4349
- close: async () => {
4350
- await teleport.close();
4351
- },
4352
- abort: async () => {
4353
- await teleport.abort();
4354
- }
4355
- };
4356
- };
4357
- };
4358
-
4359
- export {
4360
- ConnectionState,
4361
- Connection,
4362
- createIceProvider,
4363
- SwarmMessenger,
4364
- Swarm,
4365
- SwarmMapper,
4366
- MAX_CONCURRENT_INITIATING_CONNECTIONS,
4367
- ConnectionLimiter,
4368
- EventType,
4369
- ConnectionLog,
4370
- SwarmNetworkManager,
4371
- FullyConnectedTopology,
4372
- MMSTTopology,
4373
- StarTopology,
4374
- MemoryTransportFactory,
4375
- MemoryTransport,
4376
- TransportKind,
4377
- createRtcTransportFactory,
4378
- RtcTransportProxy,
4379
- RtcTransportProxyFactory,
4380
- RtcTransportService,
4381
- createTeleportProtocolFactory
4382
- };
4383
- //# sourceMappingURL=chunk-4VO725JT.mjs.map