@dxos/network-manager 0.6.13 → 0.6.14-main.2b6a0f3

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