@dxos/messaging 0.8.4-main.ae835ea → 0.8.4-main.bc2380dfbc

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 (62) hide show
  1. package/LICENSE +102 -5
  2. package/dist/lib/neutral/chunk-EC4H56J5.mjs +497 -0
  3. package/dist/lib/neutral/chunk-EC4H56J5.mjs.map +7 -0
  4. package/dist/lib/neutral/index.mjs +1249 -0
  5. package/dist/lib/neutral/index.mjs.map +7 -0
  6. package/dist/lib/neutral/meta.json +1 -0
  7. package/dist/lib/{browser → neutral}/testing/index.mjs +4 -9
  8. package/dist/lib/neutral/testing/index.mjs.map +7 -0
  9. package/dist/types/src/messenger-monitor.d.ts.map +1 -1
  10. package/dist/types/src/messenger.blueprint-test.d.ts +1 -1
  11. package/dist/types/src/messenger.blueprint-test.d.ts.map +1 -1
  12. package/dist/types/src/messenger.d.ts +3 -2
  13. package/dist/types/src/messenger.d.ts.map +1 -1
  14. package/dist/types/src/signal-client/signal-client-monitor.d.ts.map +1 -1
  15. package/dist/types/src/signal-client/signal-client.d.ts +5 -6
  16. package/dist/types/src/signal-client/signal-client.d.ts.map +1 -1
  17. package/dist/types/src/signal-client/signal-local-state.d.ts.map +1 -1
  18. package/dist/types/src/signal-client/signal-rpc-client-monitor.d.ts.map +1 -1
  19. package/dist/types/src/signal-client/signal-rpc-client.d.ts +3 -3
  20. package/dist/types/src/signal-client/signal-rpc-client.d.ts.map +1 -1
  21. package/dist/types/src/signal-manager/edge-signal-manager.d.ts +5 -5
  22. package/dist/types/src/signal-manager/edge-signal-manager.d.ts.map +1 -1
  23. package/dist/types/src/signal-manager/memory-signal-manager.d.ts +5 -4
  24. package/dist/types/src/signal-manager/memory-signal-manager.d.ts.map +1 -1
  25. package/dist/types/src/signal-manager/utils.d.ts.map +1 -1
  26. package/dist/types/src/signal-manager/websocket-signal-manager-monitor.d.ts.map +1 -1
  27. package/dist/types/src/signal-manager/websocket-signal-manager.d.ts +5 -6
  28. package/dist/types/src/signal-manager/websocket-signal-manager.d.ts.map +1 -1
  29. package/dist/types/src/signal-methods.d.ts +5 -5
  30. package/dist/types/src/signal-methods.d.ts.map +1 -1
  31. package/dist/types/src/testing/test-builder.d.ts.map +1 -1
  32. package/dist/types/src/testing/test-peer.d.ts.map +1 -1
  33. package/dist/types/src/testing/utils.d.ts.map +1 -1
  34. package/dist/types/tsconfig.tsbuildinfo +1 -1
  35. package/package.json +25 -30
  36. package/src/messenger.blueprint-test.ts +13 -12
  37. package/src/messenger.ts +37 -32
  38. package/src/signal-client/signal-client.node.test.ts +9 -9
  39. package/src/signal-client/signal-client.ts +6 -10
  40. package/src/signal-client/signal-local-state.ts +0 -1
  41. package/src/signal-client/signal-rpc-client.ts +4 -6
  42. package/src/signal-manager/edge-signal-manager.ts +10 -7
  43. package/src/signal-manager/memory-signal-manager.ts +17 -15
  44. package/src/signal-manager/websocket-signal-manager.node.test.ts +13 -13
  45. package/src/signal-manager/websocket-signal-manager.ts +9 -16
  46. package/src/signal-methods.ts +5 -5
  47. package/src/testing/test-builder.ts +4 -3
  48. package/src/testing/test-peer.ts +0 -1
  49. package/src/testing/utils.ts +0 -1
  50. package/dist/lib/browser/chunk-L7NDSF6K.mjs +0 -2380
  51. package/dist/lib/browser/chunk-L7NDSF6K.mjs.map +0 -7
  52. package/dist/lib/browser/index.mjs +0 -22
  53. package/dist/lib/browser/index.mjs.map +0 -7
  54. package/dist/lib/browser/meta.json +0 -1
  55. package/dist/lib/browser/testing/index.mjs.map +0 -7
  56. package/dist/lib/node-esm/chunk-PVWR5V42.mjs +0 -2380
  57. package/dist/lib/node-esm/chunk-PVWR5V42.mjs.map +0 -7
  58. package/dist/lib/node-esm/index.mjs +0 -22
  59. package/dist/lib/node-esm/index.mjs.map +0 -7
  60. package/dist/lib/node-esm/meta.json +0 -1
  61. package/dist/lib/node-esm/testing/index.mjs +0 -149
  62. package/dist/lib/node-esm/testing/index.mjs.map +0 -7
@@ -1,2380 +0,0 @@
1
- import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
2
-
3
- // src/messenger.ts
4
- import { TimeoutError, scheduleExponentialBackoffTaskInterval, scheduleTask, scheduleTaskInterval } from "@dxos/async";
5
- import { Context } from "@dxos/context";
6
- import { invariant } from "@dxos/invariant";
7
- import { PublicKey } from "@dxos/keys";
8
- import { log } from "@dxos/log";
9
- import { TimeoutError as ProtocolTimeoutError, trace as trace2 } from "@dxos/protocols";
10
- import { schema } from "@dxos/protocols/proto";
11
- import { ComplexMap, ComplexSet } from "@dxos/util";
12
-
13
- // src/messenger-monitor.ts
14
- import { trace } from "@dxos/tracing";
15
- var MessengerMonitor = class {
16
- recordMessageAckFailed() {
17
- trace.metrics.increment("dxos.mesh.signal.messenger.failed-ack", 1);
18
- }
19
- recordReliableMessage(params) {
20
- trace.metrics.increment("dxos.mesh.signal.messenger.reliable-send", 1, {
21
- tags: {
22
- success: params.sent,
23
- attempts: params.sendAttempts
24
- }
25
- });
26
- }
27
- };
28
-
29
- // src/timeouts.ts
30
- var MESSAGE_TIMEOUT = 1e4;
31
-
32
- // src/messenger.ts
33
- var __dxlog_file = "/__w/dxos/dxos/packages/core/mesh/messaging/src/messenger.ts";
34
- var ReliablePayload = schema.getCodecForType("dxos.mesh.messaging.ReliablePayload");
35
- var Acknowledgement = schema.getCodecForType("dxos.mesh.messaging.Acknowledgement");
36
- var RECEIVED_MESSAGES_GC_INTERVAL = 12e4;
37
- var Messenger = class {
38
- _monitor = new MessengerMonitor();
39
- _signalManager;
40
- // { peerId, payloadType } => listeners set
41
- _listeners = new ComplexMap(({ peerId, payloadType }) => peerId + payloadType);
42
- // peerId => listeners set
43
- _defaultListeners = /* @__PURE__ */ new Map();
44
- _onAckCallbacks = new ComplexMap(PublicKey.hash);
45
- _receivedMessages = new ComplexSet(PublicKey.hash);
46
- /**
47
- * Keys scheduled to be cleared from _receivedMessages on the next iteration.
48
- */
49
- _toClear = new ComplexSet(PublicKey.hash);
50
- _ctx;
51
- _closed = true;
52
- _retryDelay;
53
- constructor({ signalManager, retryDelay = 1e3 }) {
54
- this._signalManager = signalManager;
55
- this._retryDelay = retryDelay;
56
- this.open();
57
- }
58
- open() {
59
- if (!this._closed) {
60
- return;
61
- }
62
- const traceId = PublicKey.random().toHex();
63
- log.trace("dxos.mesh.messenger.open", trace2.begin({
64
- id: traceId
65
- }), {
66
- F: __dxlog_file,
67
- L: 72,
68
- S: this,
69
- C: (f, a) => f(...a)
70
- });
71
- this._ctx = new Context({
72
- onError: (err) => log.catch(err, void 0, {
73
- F: __dxlog_file,
74
- L: 74,
75
- S: this,
76
- C: (f, a) => f(...a)
77
- })
78
- }, {
79
- F: __dxlog_file,
80
- L: 73
81
- });
82
- this._ctx.onDispose(this._signalManager.onMessage.on(async (message) => {
83
- log("received message", {
84
- from: message.author
85
- }, {
86
- F: __dxlog_file,
87
- L: 78,
88
- S: this,
89
- C: (f, a) => f(...a)
90
- });
91
- await this._handleMessage(message);
92
- }));
93
- scheduleTaskInterval(this._ctx, async () => {
94
- this._performGc();
95
- }, RECEIVED_MESSAGES_GC_INTERVAL);
96
- this._closed = false;
97
- log.trace("dxos.mesh.messenger.open", trace2.end({
98
- id: traceId
99
- }), {
100
- F: __dxlog_file,
101
- L: 93,
102
- S: this,
103
- C: (f, a) => f(...a)
104
- });
105
- }
106
- async close() {
107
- if (this._closed) {
108
- return;
109
- }
110
- this._closed = true;
111
- await this._ctx.dispose();
112
- }
113
- async sendMessage({ author, recipient, payload }) {
114
- invariant(!this._closed, "Closed", {
115
- F: __dxlog_file,
116
- L: 105,
117
- S: this,
118
- A: [
119
- "!this._closed",
120
- "'Closed'"
121
- ]
122
- });
123
- const messageContext = this._ctx.derive();
124
- const reliablePayload = {
125
- messageId: PublicKey.random(),
126
- payload
127
- };
128
- invariant(!this._onAckCallbacks.has(reliablePayload.messageId), void 0, {
129
- F: __dxlog_file,
130
- L: 112,
131
- S: this,
132
- A: [
133
- "!this._onAckCallbacks.has(reliablePayload.messageId!)",
134
- ""
135
- ]
136
- });
137
- log("send message", {
138
- messageId: reliablePayload.messageId,
139
- author,
140
- recipient
141
- }, {
142
- F: __dxlog_file,
143
- L: 113,
144
- S: this,
145
- C: (f, a) => f(...a)
146
- });
147
- let messageReceived;
148
- let timeoutHit;
149
- let sendAttempts = 0;
150
- const promise = new Promise((resolve, reject) => {
151
- messageReceived = resolve;
152
- timeoutHit = reject;
153
- });
154
- scheduleExponentialBackoffTaskInterval(messageContext, async () => {
155
- log("retrying message", {
156
- messageId: reliablePayload.messageId
157
- }, {
158
- F: __dxlog_file,
159
- L: 128,
160
- S: this,
161
- C: (f, a) => f(...a)
162
- });
163
- sendAttempts++;
164
- await this._encodeAndSend({
165
- author,
166
- recipient,
167
- reliablePayload
168
- }).catch((err) => log("failed to send message", {
169
- err
170
- }, {
171
- F: __dxlog_file,
172
- L: 131,
173
- S: this,
174
- C: (f, a) => f(...a)
175
- }));
176
- }, this._retryDelay);
177
- scheduleTask(messageContext, () => {
178
- log("message not delivered", {
179
- messageId: reliablePayload.messageId
180
- }, {
181
- F: __dxlog_file,
182
- L: 140,
183
- S: this,
184
- C: (f, a) => f(...a)
185
- });
186
- this._onAckCallbacks.delete(reliablePayload.messageId);
187
- timeoutHit(new ProtocolTimeoutError("signaling message not delivered", new TimeoutError(MESSAGE_TIMEOUT, "Message not delivered")));
188
- void messageContext.dispose();
189
- this._monitor.recordReliableMessage({
190
- sendAttempts,
191
- sent: false
192
- });
193
- }, MESSAGE_TIMEOUT);
194
- this._onAckCallbacks.set(reliablePayload.messageId, () => {
195
- messageReceived();
196
- this._onAckCallbacks.delete(reliablePayload.messageId);
197
- void messageContext.dispose();
198
- this._monitor.recordReliableMessage({
199
- sendAttempts,
200
- sent: true
201
- });
202
- });
203
- await this._encodeAndSend({
204
- author,
205
- recipient,
206
- reliablePayload
207
- });
208
- return promise;
209
- }
210
- /**
211
- * Subscribes onMessage function to messages that contains payload with payloadType.
212
- * @param payloadType if not specified, onMessage will be subscribed to all types of messages.
213
- */
214
- async listen({ peer, payloadType, onMessage }) {
215
- invariant(!this._closed, "Closed", {
216
- F: __dxlog_file,
217
- L: 178,
218
- S: this,
219
- A: [
220
- "!this._closed",
221
- "'Closed'"
222
- ]
223
- });
224
- await this._signalManager.subscribeMessages(peer);
225
- let listeners;
226
- invariant(peer.peerKey, "Peer key is required", {
227
- F: __dxlog_file,
228
- L: 182,
229
- S: this,
230
- A: [
231
- "peer.peerKey",
232
- "'Peer key is required'"
233
- ]
234
- });
235
- if (!payloadType) {
236
- listeners = this._defaultListeners.get(peer.peerKey);
237
- if (!listeners) {
238
- listeners = /* @__PURE__ */ new Set();
239
- this._defaultListeners.set(peer.peerKey, listeners);
240
- }
241
- } else {
242
- listeners = this._listeners.get({
243
- peerId: peer.peerKey,
244
- payloadType
245
- });
246
- if (!listeners) {
247
- listeners = /* @__PURE__ */ new Set();
248
- this._listeners.set({
249
- peerId: peer.peerKey,
250
- payloadType
251
- }, listeners);
252
- }
253
- }
254
- listeners.add(onMessage);
255
- return {
256
- unsubscribe: async () => {
257
- listeners.delete(onMessage);
258
- }
259
- };
260
- }
261
- async _encodeAndSend({ author, recipient, reliablePayload }) {
262
- await this._signalManager.sendMessage({
263
- author,
264
- recipient,
265
- payload: {
266
- type_url: "dxos.mesh.messaging.ReliablePayload",
267
- value: ReliablePayload.encode(reliablePayload, {
268
- preserveAny: true
269
- })
270
- }
271
- });
272
- }
273
- async _handleMessage(message) {
274
- switch (message.payload.type_url) {
275
- case "dxos.mesh.messaging.ReliablePayload": {
276
- await this._handleReliablePayload(message);
277
- break;
278
- }
279
- case "dxos.mesh.messaging.Acknowledgement": {
280
- await this._handleAcknowledgement({
281
- payload: message.payload
282
- });
283
- break;
284
- }
285
- }
286
- }
287
- async _handleReliablePayload({ author, recipient, payload }) {
288
- invariant(payload.type_url === "dxos.mesh.messaging.ReliablePayload", void 0, {
289
- F: __dxlog_file,
290
- L: 240,
291
- S: this,
292
- A: [
293
- "payload.type_url === 'dxos.mesh.messaging.ReliablePayload'",
294
- ""
295
- ]
296
- });
297
- const reliablePayload = ReliablePayload.decode(payload.value, {
298
- preserveAny: true
299
- });
300
- log("handling message", {
301
- messageId: reliablePayload.messageId
302
- }, {
303
- F: __dxlog_file,
304
- L: 243,
305
- S: this,
306
- C: (f, a) => f(...a)
307
- });
308
- try {
309
- await this._sendAcknowledgement({
310
- author,
311
- recipient,
312
- messageId: reliablePayload.messageId
313
- });
314
- } catch (err) {
315
- this._monitor.recordMessageAckFailed();
316
- throw err;
317
- }
318
- if (this._receivedMessages.has(reliablePayload.messageId)) {
319
- return;
320
- }
321
- this._receivedMessages.add(reliablePayload.messageId);
322
- await this._callListeners({
323
- author,
324
- recipient,
325
- payload: reliablePayload.payload
326
- });
327
- }
328
- async _handleAcknowledgement({ payload }) {
329
- invariant(payload.type_url === "dxos.mesh.messaging.Acknowledgement", void 0, {
330
- F: __dxlog_file,
331
- L: 271,
332
- S: this,
333
- A: [
334
- "payload.type_url === 'dxos.mesh.messaging.Acknowledgement'",
335
- ""
336
- ]
337
- });
338
- this._onAckCallbacks.get(Acknowledgement.decode(payload.value).messageId)?.();
339
- }
340
- async _sendAcknowledgement({ author, recipient, messageId }) {
341
- log("sending ACK", {
342
- messageId,
343
- from: recipient,
344
- to: author
345
- }, {
346
- F: __dxlog_file,
347
- L: 284,
348
- S: this,
349
- C: (f, a) => f(...a)
350
- });
351
- await this._signalManager.sendMessage({
352
- author: recipient,
353
- recipient: author,
354
- payload: {
355
- type_url: "dxos.mesh.messaging.Acknowledgement",
356
- value: Acknowledgement.encode({
357
- messageId
358
- })
359
- }
360
- });
361
- }
362
- async _callListeners(message) {
363
- {
364
- invariant(message.recipient.peerKey, "Peer key is required", {
365
- F: __dxlog_file,
366
- L: 298,
367
- S: this,
368
- A: [
369
- "message.recipient.peerKey",
370
- "'Peer key is required'"
371
- ]
372
- });
373
- const defaultListenerMap = this._defaultListeners.get(message.recipient.peerKey);
374
- if (defaultListenerMap) {
375
- for (const listener of defaultListenerMap) {
376
- await listener(message);
377
- }
378
- }
379
- }
380
- {
381
- const listenerMap = this._listeners.get({
382
- peerId: message.recipient.peerKey,
383
- payloadType: message.payload.type_url
384
- });
385
- if (listenerMap) {
386
- for (const listener of listenerMap) {
387
- await listener(message);
388
- }
389
- }
390
- }
391
- }
392
- _performGc() {
393
- const start = performance.now();
394
- for (const key of this._toClear.keys()) {
395
- this._receivedMessages.delete(key);
396
- }
397
- this._toClear.clear();
398
- for (const key of this._receivedMessages.keys()) {
399
- this._toClear.add(key);
400
- }
401
- const elapsed = performance.now() - start;
402
- if (elapsed > 100) {
403
- log.warn("GC took too long", {
404
- elapsed
405
- }, {
406
- F: __dxlog_file,
407
- L: 333,
408
- S: this,
409
- C: (f, a) => f(...a)
410
- });
411
- }
412
- }
413
- };
414
-
415
- // src/signal-client/signal-client.ts
416
- import { DeferredTask, Event as Event2, Trigger as Trigger2, scheduleTask as scheduleTask2, scheduleTaskInterval as scheduleTaskInterval3, sleep } from "@dxos/async";
417
- import { Resource, cancelWithContext as cancelWithContext2 } from "@dxos/context";
418
- import { invariant as invariant3 } from "@dxos/invariant";
419
- import { PublicKey as PublicKey4 } from "@dxos/keys";
420
- import { log as log4 } from "@dxos/log";
421
- import { trace as trace6 } from "@dxos/protocols";
422
- import { SignalState } from "@dxos/protocols/proto/dxos/mesh/signal";
423
-
424
- // src/signal-client/signal-client-monitor.ts
425
- import { trace as trace3 } from "@dxos/tracing";
426
- var SignalClientMonitor = class {
427
- _performance = {
428
- sentMessages: 0,
429
- receivedMessages: 0,
430
- reconnectCounter: 0,
431
- joinCounter: 0,
432
- leaveCounter: 0
433
- };
434
- /**
435
- * Timestamp of when the connection attempt was began.
436
- */
437
- _connectionStarted = /* @__PURE__ */ new Date();
438
- /**
439
- * Timestamp of last state change.
440
- */
441
- _lastStateChange = /* @__PURE__ */ new Date();
442
- getRecordedTimestamps() {
443
- return {
444
- connectionStarted: this._connectionStarted,
445
- lastStateChange: this._lastStateChange
446
- };
447
- }
448
- recordStateChangeTime() {
449
- this._lastStateChange = /* @__PURE__ */ new Date();
450
- }
451
- recordConnectionStartTime() {
452
- this._connectionStarted = /* @__PURE__ */ new Date();
453
- }
454
- recordReconnect(params) {
455
- this._performance.reconnectCounter++;
456
- trace3.metrics.increment("dxos.mesh.signal.signal-client.reconnect", 1, {
457
- tags: {
458
- success: params.success
459
- }
460
- });
461
- }
462
- recordJoin() {
463
- this._performance.joinCounter++;
464
- }
465
- recordLeave() {
466
- this._performance.leaveCounter++;
467
- }
468
- recordMessageReceived(message) {
469
- this._performance.receivedMessages++;
470
- trace3.metrics.increment("dxos.mesh.signal.signal-client.received-total", 1, {
471
- tags: createIdentityTags(message)
472
- });
473
- trace3.metrics.distribution("dxos.mesh.signal.signal-client.bytes-in", getByteCount(message), {
474
- tags: createIdentityTags(message)
475
- });
476
- }
477
- async recordMessageSending(message, sendMessage) {
478
- this._performance.sentMessages++;
479
- const tags = createIdentityTags(message);
480
- let success = true;
481
- try {
482
- const reqStart = Date.now();
483
- await sendMessage();
484
- const reqDuration = Date.now() - reqStart;
485
- trace3.metrics.distribution("dxos.mesh.signal.signal-client.send-duration", reqDuration, {
486
- tags
487
- });
488
- trace3.metrics.distribution("dxos.mesh.signal.signal-client.bytes-out", getByteCount(message), {
489
- tags
490
- });
491
- } catch (err) {
492
- success = false;
493
- }
494
- trace3.metrics.increment("dxos.mesh.signal.signal-client.sent-total", 1, {
495
- tags: {
496
- ...tags,
497
- success
498
- }
499
- });
500
- }
501
- recordStreamCloseErrors(count) {
502
- trace3.metrics.increment("dxos.mesh.signal.signal-client.stream-close-errors", count);
503
- }
504
- recordReconciliation(params) {
505
- trace3.metrics.increment("dxos.mesh.signal.signal-client.reconciliation", 1, {
506
- tags: {
507
- success: params.success
508
- }
509
- });
510
- }
511
- };
512
- var getByteCount = (message) => {
513
- return message.author.peerKey.length + message.recipient.peerKey.length + message.payload.type_url.length + message.payload.value.length;
514
- };
515
- var createIdentityTags = (message) => {
516
- return {
517
- peer: message.author.peerKey
518
- };
519
- };
520
-
521
- // src/signal-client/signal-local-state.ts
522
- import { Event, asyncTimeout } from "@dxos/async";
523
- import { cancelWithContext } from "@dxos/context";
524
- import { PublicKey as PublicKey2 } from "@dxos/keys";
525
- import { log as log2 } from "@dxos/log";
526
- import { ComplexMap as ComplexMap2, ComplexSet as ComplexSet2, safeAwaitAll } from "@dxos/util";
527
- var __dxlog_file2 = "/__w/dxos/dxos/packages/core/mesh/messaging/src/signal-client/signal-local-state.ts";
528
- var SignalLocalState = class {
529
- _onMessage;
530
- _onSwarmEvent;
531
- /**
532
- * Swarm events streams. Keys represent actually joined topic and peerId.
533
- */
534
- _swarmStreams = new ComplexMap2(({ topic, peerId }) => topic.toHex() + peerId.toHex());
535
- /**
536
- * Represent desired joined topic and peerId.
537
- */
538
- _joinedTopics = new ComplexSet2(({ topic, peerId }) => topic.toHex() + peerId.toHex());
539
- /**
540
- * Represent desired message subscriptions.
541
- */
542
- _subscribedMessages = new ComplexSet2(({ peerId }) => peerId.toHex());
543
- /**
544
- * Message streams. Keys represents actually subscribed peers.
545
- * @internal
546
- */
547
- messageStreams = new ComplexMap2((key) => key.toHex());
548
- /**
549
- * Event to use in tests to wait till subscription is successfully established.
550
- * @internal
551
- */
552
- reconciled = new Event();
553
- constructor(_onMessage, _onSwarmEvent) {
554
- this._onMessage = _onMessage;
555
- this._onSwarmEvent = _onSwarmEvent;
556
- }
557
- async safeCloseStreams() {
558
- const streams = [
559
- ...this._swarmStreams.values()
560
- ].concat([
561
- ...this.messageStreams.values()
562
- ]);
563
- this._swarmStreams.clear();
564
- this.messageStreams.clear();
565
- const failureCount = (await safeAwaitAll(streams, (s) => s.close())).length;
566
- return {
567
- failureCount
568
- };
569
- }
570
- join({ topic, peerId }) {
571
- this._joinedTopics.add({
572
- topic,
573
- peerId
574
- });
575
- }
576
- leave({ topic, peerId }) {
577
- void this._swarmStreams.get({
578
- topic,
579
- peerId
580
- })?.close();
581
- this._swarmStreams.delete({
582
- topic,
583
- peerId
584
- });
585
- this._joinedTopics.delete({
586
- topic,
587
- peerId
588
- });
589
- }
590
- subscribeMessages(peerId) {
591
- this._subscribedMessages.add({
592
- peerId
593
- });
594
- }
595
- unsubscribeMessages(peerId) {
596
- log2("unsubscribing from messages", {
597
- peerId
598
- }, {
599
- F: __dxlog_file2,
600
- L: 80,
601
- S: this,
602
- C: (f, a) => f(...a)
603
- });
604
- this._subscribedMessages.delete({
605
- peerId
606
- });
607
- void this.messageStreams.get(peerId)?.close();
608
- this.messageStreams.delete(peerId);
609
- }
610
- async reconcile(ctx, client) {
611
- await this._reconcileSwarmSubscriptions(ctx, client);
612
- await this._reconcileMessageSubscriptions(ctx, client);
613
- this.reconciled.emit();
614
- }
615
- async _reconcileSwarmSubscriptions(ctx, client) {
616
- for (const { topic, peerId } of this._swarmStreams.keys()) {
617
- if (this._joinedTopics.has({
618
- topic,
619
- peerId
620
- })) {
621
- continue;
622
- }
623
- void this._swarmStreams.get({
624
- topic,
625
- peerId
626
- })?.close();
627
- this._swarmStreams.delete({
628
- topic,
629
- peerId
630
- });
631
- }
632
- for (const { topic, peerId } of this._joinedTopics.values()) {
633
- if (this._swarmStreams.has({
634
- topic,
635
- peerId
636
- })) {
637
- continue;
638
- }
639
- const swarmStream = await asyncTimeout(cancelWithContext(ctx, client.join({
640
- topic,
641
- peerId
642
- })), 5e3);
643
- swarmStream.subscribe(async (swarmEvent) => {
644
- if (this._joinedTopics.has({
645
- topic,
646
- peerId
647
- })) {
648
- log2("swarm event", {
649
- swarmEvent
650
- }, {
651
- F: __dxlog_file2,
652
- L: 116,
653
- S: this,
654
- C: (f, a) => f(...a)
655
- });
656
- const event = swarmEvent.peerAvailable ? {
657
- topic,
658
- peerAvailable: {
659
- ...swarmEvent.peerAvailable,
660
- peer: {
661
- peerKey: PublicKey2.from(swarmEvent.peerAvailable.peer).toHex()
662
- }
663
- }
664
- } : {
665
- topic,
666
- peerLeft: {
667
- ...swarmEvent.peerLeft,
668
- peer: {
669
- peerKey: PublicKey2.from(swarmEvent.peerLeft.peer).toHex()
670
- }
671
- }
672
- };
673
- await this._onSwarmEvent(event);
674
- }
675
- });
676
- this._swarmStreams.set({
677
- topic,
678
- peerId
679
- }, swarmStream);
680
- }
681
- }
682
- async _reconcileMessageSubscriptions(ctx, client) {
683
- for (const peerId of this.messageStreams.keys()) {
684
- if (this._subscribedMessages.has({
685
- peerId
686
- })) {
687
- continue;
688
- }
689
- void this.messageStreams.get(peerId)?.close();
690
- this.messageStreams.delete(peerId);
691
- }
692
- for (const { peerId } of this._subscribedMessages.values()) {
693
- if (this.messageStreams.has(peerId)) {
694
- continue;
695
- }
696
- const messageStream = await asyncTimeout(cancelWithContext(ctx, client.receiveMessages(peerId)), 5e3);
697
- messageStream.subscribe(async (signalMessage) => {
698
- if (this._subscribedMessages.has({
699
- peerId
700
- })) {
701
- const message = {
702
- author: {
703
- peerKey: PublicKey2.from(signalMessage.author).toHex()
704
- },
705
- recipient: {
706
- peerKey: PublicKey2.from(signalMessage.recipient).toHex()
707
- },
708
- payload: signalMessage.payload
709
- };
710
- await this._onMessage(message);
711
- }
712
- });
713
- this.messageStreams.set(peerId, messageStream);
714
- }
715
- }
716
- };
717
-
718
- // src/signal-client/signal-rpc-client.ts
719
- import WebSocket from "isomorphic-ws";
720
- import { TimeoutError as TimeoutError2, Trigger, scheduleTaskInterval as scheduleTaskInterval2 } from "@dxos/async";
721
- import { Context as Context2 } from "@dxos/context";
722
- import { invariant as invariant2 } from "@dxos/invariant";
723
- import { PublicKey as PublicKey3 } from "@dxos/keys";
724
- import { log as log3 } from "@dxos/log";
725
- import { trace as trace5 } from "@dxos/protocols";
726
- import { schema as schema2 } from "@dxos/protocols/proto";
727
- import { createProtoRpcPeer } from "@dxos/rpc";
728
-
729
- // src/signal-client/signal-rpc-client-monitor.ts
730
- import { trace as trace4 } from "@dxos/tracing";
731
- var SignalRpcClientMonitor = class {
732
- recordClientCloseFailure(params) {
733
- trace4.metrics.increment("dxos.mesh.signal.signal-rpc-client.close-failure", 1, {
734
- tags: {
735
- reason: params.failureReason
736
- }
737
- });
738
- }
739
- };
740
-
741
- // src/signal-client/signal-rpc-client.ts
742
- var __dxlog_file3 = "/__w/dxos/dxos/packages/core/mesh/messaging/src/signal-client/signal-rpc-client.ts";
743
- var SIGNAL_KEEPALIVE_INTERVAL = 1e4;
744
- var SignalRPCClient = class {
745
- _socket;
746
- _rpc;
747
- _connectTrigger = new Trigger();
748
- _keepaliveCtx;
749
- _closed = false;
750
- _url;
751
- _callbacks;
752
- _closeComplete = new Trigger();
753
- _monitor = new SignalRpcClientMonitor();
754
- constructor({ url, callbacks = {} }) {
755
- const traceId = PublicKey3.random().toHex();
756
- log3.trace("dxos.mesh.signal-rpc-client.constructor", trace5.begin({
757
- id: traceId
758
- }), {
759
- F: __dxlog_file3,
760
- L: 66,
761
- S: this,
762
- C: (f, a) => f(...a)
763
- });
764
- this._url = url;
765
- this._callbacks = callbacks;
766
- this._socket = new WebSocket(this._url);
767
- this._rpc = createProtoRpcPeer({
768
- requested: {
769
- Signal: schema2.getService("dxos.mesh.signal.Signal")
770
- },
771
- noHandshake: true,
772
- port: {
773
- send: (msg) => {
774
- if (this._closed) {
775
- return;
776
- }
777
- try {
778
- this._socket.send(msg);
779
- } catch (err) {
780
- log3.warn("send error", err, {
781
- F: __dxlog_file3,
782
- L: 85,
783
- S: this,
784
- C: (f, a) => f(...a)
785
- });
786
- }
787
- },
788
- subscribe: (cb) => {
789
- this._socket.onmessage = async (msg) => {
790
- if (typeof Blob !== "undefined" && msg.data instanceof Blob) {
791
- cb(Buffer.from(await msg.data.arrayBuffer()));
792
- } else {
793
- cb(msg.data);
794
- }
795
- };
796
- }
797
- },
798
- encodingOptions: {
799
- preserveAny: true
800
- }
801
- });
802
- this._socket.onopen = async () => {
803
- try {
804
- await this._rpc.open();
805
- if (this._closed) {
806
- await this._safeCloseRpc();
807
- return;
808
- }
809
- log3(`RPC open ${this._url}`, void 0, {
810
- F: __dxlog_file3,
811
- L: 110,
812
- S: this,
813
- C: (f, a) => f(...a)
814
- });
815
- this._callbacks.onConnected?.();
816
- this._connectTrigger.wake();
817
- this._keepaliveCtx = new Context2(void 0, {
818
- F: __dxlog_file3,
819
- L: 113
820
- });
821
- scheduleTaskInterval2(this._keepaliveCtx, async () => {
822
- this._socket?.send("__ping__");
823
- }, SIGNAL_KEEPALIVE_INTERVAL);
824
- } catch (err) {
825
- this._callbacks.onError?.(err);
826
- this._socket.close();
827
- this._closed = true;
828
- }
829
- };
830
- this._socket.onclose = async () => {
831
- log3(`Disconnected ${this._url}`, void 0, {
832
- F: __dxlog_file3,
833
- L: 133,
834
- S: this,
835
- C: (f, a) => f(...a)
836
- });
837
- this._callbacks.onDisconnected?.();
838
- this._closeComplete.wake();
839
- await this.close();
840
- };
841
- this._socket.onerror = async (event) => {
842
- if (this._closed) {
843
- this._socket.close();
844
- return;
845
- }
846
- this._closed = true;
847
- this._callbacks.onError?.(event.error ?? new Error(event.message));
848
- await this._safeCloseRpc();
849
- log3.warn(`Socket ${event.type ?? "unknown"} error`, {
850
- message: event.message,
851
- url: this._url
852
- }, {
853
- F: __dxlog_file3,
854
- L: 149,
855
- S: this,
856
- C: (f, a) => f(...a)
857
- });
858
- };
859
- log3.trace("dxos.mesh.signal-rpc-client.constructor", trace5.end({
860
- id: traceId
861
- }), {
862
- F: __dxlog_file3,
863
- L: 152,
864
- S: this,
865
- C: (f, a) => f(...a)
866
- });
867
- }
868
- async close() {
869
- if (this._closed) {
870
- return;
871
- }
872
- this._closed = true;
873
- await this._keepaliveCtx?.dispose();
874
- try {
875
- await this._safeCloseRpc();
876
- if (this._socket.readyState === WebSocket.OPEN || this._socket.readyState === WebSocket.CONNECTING) {
877
- this._socket.close();
878
- }
879
- await this._closeComplete.wait({
880
- timeout: 1e3
881
- });
882
- } catch (err) {
883
- const failureReason = err instanceof TimeoutError2 ? "timeout" : err?.constructor?.name ?? "unknown";
884
- this._monitor.recordClientCloseFailure({
885
- failureReason
886
- });
887
- }
888
- }
889
- async join({ topic, peerId }) {
890
- log3("join", {
891
- topic,
892
- peerId,
893
- metadata: this._callbacks?.getMetadata?.()
894
- }, {
895
- F: __dxlog_file3,
896
- L: 178,
897
- S: this,
898
- C: (f, a) => f(...a)
899
- });
900
- invariant2(!this._closed, "SignalRPCClient is closed", {
901
- F: __dxlog_file3,
902
- L: 179,
903
- S: this,
904
- A: [
905
- "!this._closed",
906
- "'SignalRPCClient is closed'"
907
- ]
908
- });
909
- await this._connectTrigger.wait();
910
- const swarmStream = this._rpc.rpc.Signal.join({
911
- swarm: topic.asUint8Array(),
912
- peer: peerId.asUint8Array(),
913
- metadata: this._callbacks?.getMetadata?.()
914
- });
915
- await swarmStream.waitUntilReady();
916
- return swarmStream;
917
- }
918
- async receiveMessages(peerId) {
919
- log3("receiveMessages", {
920
- peerId
921
- }, {
922
- F: __dxlog_file3,
923
- L: 191,
924
- S: this,
925
- C: (f, a) => f(...a)
926
- });
927
- invariant2(!this._closed, "SignalRPCClient is closed", {
928
- F: __dxlog_file3,
929
- L: 192,
930
- S: this,
931
- A: [
932
- "!this._closed",
933
- "'SignalRPCClient is closed'"
934
- ]
935
- });
936
- await this._connectTrigger.wait();
937
- const messageStream = this._rpc.rpc.Signal.receiveMessages({
938
- peer: peerId.asUint8Array()
939
- });
940
- await messageStream.waitUntilReady();
941
- return messageStream;
942
- }
943
- async sendMessage({ author, recipient, payload }) {
944
- log3("sendMessage", {
945
- author,
946
- recipient,
947
- payload,
948
- metadata: this._callbacks?.getMetadata?.()
949
- }, {
950
- F: __dxlog_file3,
951
- L: 210,
952
- S: this,
953
- C: (f, a) => f(...a)
954
- });
955
- invariant2(!this._closed, "SignalRPCClient is closed", {
956
- F: __dxlog_file3,
957
- L: 211,
958
- S: this,
959
- A: [
960
- "!this._closed",
961
- "'SignalRPCClient is closed'"
962
- ]
963
- });
964
- await this._connectTrigger.wait();
965
- await this._rpc.rpc.Signal.sendMessage({
966
- author: author.asUint8Array(),
967
- recipient: recipient.asUint8Array(),
968
- payload,
969
- metadata: this._callbacks?.getMetadata?.()
970
- });
971
- }
972
- async _safeCloseRpc() {
973
- try {
974
- this._connectTrigger.reset();
975
- await this._rpc.close();
976
- } catch (err) {
977
- log3.catch(err, void 0, {
978
- F: __dxlog_file3,
979
- L: 226,
980
- S: this,
981
- C: (f, a) => f(...a)
982
- });
983
- }
984
- }
985
- };
986
-
987
- // src/signal-client/signal-client.ts
988
- var __dxlog_file4 = "/__w/dxos/dxos/packages/core/mesh/messaging/src/signal-client/signal-client.ts";
989
- var DEFAULT_RECONNECT_TIMEOUT = 100;
990
- var MAX_RECONNECT_TIMEOUT = 5e3;
991
- var ERROR_RECONCILE_DELAY = 1e3;
992
- var RECONCILE_INTERVAL = 5e3;
993
- var SignalClient = class extends Resource {
994
- _host;
995
- _getMetadata;
996
- _monitor = new SignalClientMonitor();
997
- _state = SignalState.CLOSED;
998
- _lastError;
999
- _lastReconciliationFailed = false;
1000
- _clientReady = new Trigger2();
1001
- _connectionCtx;
1002
- _client;
1003
- _reconcileTask;
1004
- _reconnectTask;
1005
- /**
1006
- * Number of milliseconds after which the connection will be attempted again in case of error.
1007
- */
1008
- _reconnectAfter = DEFAULT_RECONNECT_TIMEOUT;
1009
- _instanceId = PublicKey4.random().toHex();
1010
- /**
1011
- * @internal
1012
- */
1013
- localState;
1014
- statusChanged = new Event2();
1015
- onMessage = new Event2();
1016
- swarmEvent = new Event2();
1017
- /**
1018
- * @param _host Signal server websocket URL.
1019
- * @param onMessage called when a new message is received.
1020
- * @param onSwarmEvent called when a new swarm event is received.
1021
- * @param _getMetadata signal-message metadata provider, called for every message.
1022
- */
1023
- constructor(_host, _getMetadata) {
1024
- super(), this._host = _host, this._getMetadata = _getMetadata;
1025
- if (!this._host.startsWith("wss://") && !this._host.startsWith("ws://")) {
1026
- throw new Error(`Signal server requires a websocket URL. Provided: ${this._host}`);
1027
- }
1028
- this.localState = new SignalLocalState(async (message) => {
1029
- this._monitor.recordMessageReceived(message);
1030
- this.onMessage.emit(message);
1031
- }, async (event) => this.swarmEvent.emit(event));
1032
- }
1033
- async _open() {
1034
- log4.trace("dxos.mesh.signal-client.open", trace6.begin({
1035
- id: this._instanceId
1036
- }), {
1037
- F: __dxlog_file4,
1038
- L: 97,
1039
- S: this,
1040
- C: (f, a) => f(...a)
1041
- });
1042
- if ([
1043
- SignalState.CONNECTED,
1044
- SignalState.CONNECTING
1045
- ].includes(this._state)) {
1046
- return;
1047
- }
1048
- this._setState(SignalState.CONNECTING);
1049
- this._reconcileTask = new DeferredTask(this._ctx, async () => {
1050
- try {
1051
- await cancelWithContext2(this._connectionCtx, this._clientReady.wait({
1052
- timeout: 5e3
1053
- }));
1054
- invariant3(this._state === SignalState.CONNECTED, "Not connected to Signal Server", {
1055
- F: __dxlog_file4,
1056
- L: 107,
1057
- S: this,
1058
- A: [
1059
- "this._state === SignalState.CONNECTED",
1060
- "'Not connected to Signal Server'"
1061
- ]
1062
- });
1063
- await this.localState.reconcile(this._connectionCtx, this._client);
1064
- this._monitor.recordReconciliation({
1065
- success: true
1066
- });
1067
- this._lastReconciliationFailed = false;
1068
- } catch (err) {
1069
- this._lastReconciliationFailed = true;
1070
- this._monitor.recordReconciliation({
1071
- success: false
1072
- });
1073
- throw err;
1074
- }
1075
- });
1076
- scheduleTaskInterval3(this._ctx, async () => {
1077
- if (this._state === SignalState.CONNECTED) {
1078
- this._reconcileTask.schedule();
1079
- }
1080
- }, RECONCILE_INTERVAL);
1081
- this._reconnectTask = new DeferredTask(this._ctx, async () => {
1082
- try {
1083
- await this._reconnect();
1084
- this._monitor.recordReconnect({
1085
- success: true
1086
- });
1087
- } catch (err) {
1088
- this._monitor.recordReconnect({
1089
- success: false
1090
- });
1091
- throw err;
1092
- }
1093
- });
1094
- this._createClient();
1095
- log4.trace("dxos.mesh.signal-client.open", trace6.end({
1096
- id: this._instanceId
1097
- }), {
1098
- F: __dxlog_file4,
1099
- L: 140,
1100
- S: this,
1101
- C: (f, a) => f(...a)
1102
- });
1103
- }
1104
- async _catch(err) {
1105
- if (this._state === SignalState.CLOSED || this._ctx.disposed) {
1106
- return;
1107
- }
1108
- if (this._state === SignalState.CONNECTED && !this._lastReconciliationFailed) {
1109
- log4.warn("SignalClient error:", err, {
1110
- F: __dxlog_file4,
1111
- L: 149,
1112
- S: this,
1113
- C: (f, a) => f(...a)
1114
- });
1115
- }
1116
- this._scheduleReconcileAfterError();
1117
- }
1118
- async _close() {
1119
- log4("closing...", void 0, {
1120
- F: __dxlog_file4,
1121
- L: 155,
1122
- S: this,
1123
- C: (f, a) => f(...a)
1124
- });
1125
- if ([
1126
- SignalState.CLOSED
1127
- ].includes(this._state)) {
1128
- return;
1129
- }
1130
- this._setState(SignalState.CLOSED);
1131
- await this._safeResetClient();
1132
- log4("closed", void 0, {
1133
- F: __dxlog_file4,
1134
- L: 163,
1135
- S: this,
1136
- C: (f, a) => f(...a)
1137
- });
1138
- }
1139
- getStatus() {
1140
- return {
1141
- host: this._host,
1142
- state: this._state,
1143
- error: this._lastError?.message,
1144
- reconnectIn: this._reconnectAfter,
1145
- ...this._monitor.getRecordedTimestamps()
1146
- };
1147
- }
1148
- async join(args) {
1149
- log4("joining", {
1150
- topic: args.topic,
1151
- peerId: args.peer.peerKey
1152
- }, {
1153
- F: __dxlog_file4,
1154
- L: 177,
1155
- S: this,
1156
- C: (f, a) => f(...a)
1157
- });
1158
- this._monitor.recordJoin();
1159
- this.localState.join({
1160
- topic: args.topic,
1161
- peerId: PublicKey4.from(args.peer.peerKey)
1162
- });
1163
- this._reconcileTask?.schedule();
1164
- }
1165
- async leave(args) {
1166
- log4("leaving", {
1167
- topic: args.topic,
1168
- peerId: args.peer.peerKey
1169
- }, {
1170
- F: __dxlog_file4,
1171
- L: 184,
1172
- S: this,
1173
- C: (f, a) => f(...a)
1174
- });
1175
- this._monitor.recordLeave();
1176
- this.localState.leave({
1177
- topic: args.topic,
1178
- peerId: PublicKey4.from(args.peer.peerKey)
1179
- });
1180
- }
1181
- async query(params) {
1182
- throw new Error("Not implemented");
1183
- }
1184
- async sendMessage(msg) {
1185
- return this._monitor.recordMessageSending(msg, async () => {
1186
- await this._clientReady.wait();
1187
- invariant3(this._state === SignalState.CONNECTED, "Not connected to Signal Server", {
1188
- F: __dxlog_file4,
1189
- L: 196,
1190
- S: this,
1191
- A: [
1192
- "this._state === SignalState.CONNECTED",
1193
- "'Not connected to Signal Server'"
1194
- ]
1195
- });
1196
- invariant3(msg.author.peerKey, "Author key required", {
1197
- F: __dxlog_file4,
1198
- L: 197,
1199
- S: this,
1200
- A: [
1201
- "msg.author.peerKey",
1202
- "'Author key required'"
1203
- ]
1204
- });
1205
- invariant3(msg.recipient.peerKey, "Recipient key required", {
1206
- F: __dxlog_file4,
1207
- L: 198,
1208
- S: this,
1209
- A: [
1210
- "msg.recipient.peerKey",
1211
- "'Recipient key required'"
1212
- ]
1213
- });
1214
- await this._client.sendMessage({
1215
- author: PublicKey4.from(msg.author.peerKey),
1216
- recipient: PublicKey4.from(msg.recipient.peerKey),
1217
- payload: msg.payload
1218
- });
1219
- });
1220
- }
1221
- async subscribeMessages(peer) {
1222
- invariant3(peer.peerKey, "Peer key required", {
1223
- F: __dxlog_file4,
1224
- L: 208,
1225
- S: this,
1226
- A: [
1227
- "peer.peerKey",
1228
- "'Peer key required'"
1229
- ]
1230
- });
1231
- log4("subscribing to messages", {
1232
- peer
1233
- }, {
1234
- F: __dxlog_file4,
1235
- L: 209,
1236
- S: this,
1237
- C: (f, a) => f(...a)
1238
- });
1239
- this.localState.subscribeMessages(PublicKey4.from(peer.peerKey));
1240
- this._reconcileTask?.schedule();
1241
- }
1242
- async unsubscribeMessages(peer) {
1243
- invariant3(peer.peerKey, "Peer key required", {
1244
- F: __dxlog_file4,
1245
- L: 215,
1246
- S: this,
1247
- A: [
1248
- "peer.peerKey",
1249
- "'Peer key required'"
1250
- ]
1251
- });
1252
- log4("unsubscribing from messages", {
1253
- peer
1254
- }, {
1255
- F: __dxlog_file4,
1256
- L: 216,
1257
- S: this,
1258
- C: (f, a) => f(...a)
1259
- });
1260
- this.localState.unsubscribeMessages(PublicKey4.from(peer.peerKey));
1261
- }
1262
- _scheduleReconcileAfterError() {
1263
- scheduleTask2(this._ctx, () => this._reconcileTask.schedule(), ERROR_RECONCILE_DELAY);
1264
- }
1265
- _createClient() {
1266
- log4("creating client", {
1267
- host: this._host,
1268
- state: this._state
1269
- }, {
1270
- F: __dxlog_file4,
1271
- L: 225,
1272
- S: this,
1273
- C: (f, a) => f(...a)
1274
- });
1275
- invariant3(!this._client, "Client already created", {
1276
- F: __dxlog_file4,
1277
- L: 226,
1278
- S: this,
1279
- A: [
1280
- "!this._client",
1281
- "'Client already created'"
1282
- ]
1283
- });
1284
- this._monitor.recordConnectionStartTime();
1285
- this._connectionCtx = this._ctx.derive();
1286
- this._connectionCtx.onDispose(async () => {
1287
- log4("connection context disposed", void 0, {
1288
- F: __dxlog_file4,
1289
- L: 233,
1290
- S: this,
1291
- C: (f, a) => f(...a)
1292
- });
1293
- const { failureCount } = await this.localState.safeCloseStreams();
1294
- this._monitor.recordStreamCloseErrors(failureCount);
1295
- });
1296
- try {
1297
- const client = new SignalRPCClient({
1298
- url: this._host,
1299
- callbacks: {
1300
- onConnected: () => {
1301
- if (client === this._client) {
1302
- log4("socket connected", void 0, {
1303
- F: __dxlog_file4,
1304
- L: 244,
1305
- S: this,
1306
- C: (f, a) => f(...a)
1307
- });
1308
- this._onConnected();
1309
- }
1310
- },
1311
- onDisconnected: () => {
1312
- if (client !== this._client) {
1313
- return;
1314
- }
1315
- log4("socket disconnected", {
1316
- state: this._state
1317
- }, {
1318
- F: __dxlog_file4,
1319
- L: 253,
1320
- S: this,
1321
- C: (f, a) => f(...a)
1322
- });
1323
- if (this._state === SignalState.ERROR) {
1324
- this._setState(SignalState.DISCONNECTED);
1325
- } else {
1326
- this._onDisconnected();
1327
- }
1328
- },
1329
- onError: (error) => {
1330
- if (client === this._client) {
1331
- log4("socket error", {
1332
- error,
1333
- state: this._state
1334
- }, {
1335
- F: __dxlog_file4,
1336
- L: 265,
1337
- S: this,
1338
- C: (f, a) => f(...a)
1339
- });
1340
- this._onDisconnected({
1341
- error
1342
- });
1343
- }
1344
- },
1345
- getMetadata: this._getMetadata
1346
- }
1347
- });
1348
- this._client = client;
1349
- } catch (error) {
1350
- this._client = void 0;
1351
- this._onDisconnected({
1352
- error
1353
- });
1354
- }
1355
- }
1356
- async _reconnect() {
1357
- log4(`reconnecting in ${this._reconnectAfter}ms`, {
1358
- state: this._state
1359
- }, {
1360
- F: __dxlog_file4,
1361
- L: 280,
1362
- S: this,
1363
- C: (f, a) => f(...a)
1364
- });
1365
- if (this._state === SignalState.RECONNECTING) {
1366
- log4.info("Signal api already reconnecting.", void 0, {
1367
- F: __dxlog_file4,
1368
- L: 283,
1369
- S: this,
1370
- C: (f, a) => f(...a)
1371
- });
1372
- return;
1373
- }
1374
- if (this._state === SignalState.CLOSED) {
1375
- return;
1376
- }
1377
- this._setState(SignalState.RECONNECTING);
1378
- await this._safeResetClient();
1379
- await cancelWithContext2(this._ctx, sleep(this._reconnectAfter));
1380
- this._createClient();
1381
- }
1382
- _onConnected() {
1383
- this._lastError = void 0;
1384
- this._lastReconciliationFailed = false;
1385
- this._reconnectAfter = DEFAULT_RECONNECT_TIMEOUT;
1386
- this._setState(SignalState.CONNECTED);
1387
- this._clientReady.wake();
1388
- this._reconcileTask.schedule();
1389
- }
1390
- _onDisconnected(options) {
1391
- this._updateReconnectTimeout();
1392
- if (this._state === SignalState.CLOSED) {
1393
- return;
1394
- }
1395
- if (options?.error) {
1396
- this._lastError = options.error;
1397
- this._setState(SignalState.ERROR);
1398
- } else {
1399
- this._setState(SignalState.DISCONNECTED);
1400
- }
1401
- this._reconnectTask.schedule();
1402
- }
1403
- _setState(newState) {
1404
- this._state = newState;
1405
- this._monitor.recordStateChangeTime();
1406
- log4("signal state changed", {
1407
- status: this.getStatus()
1408
- }, {
1409
- F: __dxlog_file4,
1410
- L: 324,
1411
- S: this,
1412
- C: (f, a) => f(...a)
1413
- });
1414
- this.statusChanged.emit(this.getStatus());
1415
- }
1416
- _updateReconnectTimeout() {
1417
- if (this._state !== SignalState.CONNECTED && this._state !== SignalState.CONNECTING) {
1418
- this._reconnectAfter *= 2;
1419
- this._reconnectAfter = Math.min(this._reconnectAfter, MAX_RECONNECT_TIMEOUT);
1420
- }
1421
- }
1422
- async _safeResetClient() {
1423
- await this._connectionCtx?.dispose();
1424
- this._connectionCtx = void 0;
1425
- this._clientReady.reset();
1426
- await this._client?.close().catch(() => {
1427
- });
1428
- this._client = void 0;
1429
- }
1430
- };
1431
-
1432
- // src/signal-methods.ts
1433
- var PeerInfoHash = ({ peerKey }) => peerKey;
1434
-
1435
- // src/signal-manager/memory-signal-manager.ts
1436
- import { Event as Event3, Trigger as Trigger3 } from "@dxos/async";
1437
- import { Context as Context3 } from "@dxos/context";
1438
- import { invariant as invariant4 } from "@dxos/invariant";
1439
- import { PublicKey as PublicKey5 } from "@dxos/keys";
1440
- import { log as log5 } from "@dxos/log";
1441
- import { schema as schema3 } from "@dxos/protocols/proto";
1442
- import { ComplexMap as ComplexMap3, ComplexSet as ComplexSet3 } from "@dxos/util";
1443
- var __dxlog_file5 = "/__w/dxos/dxos/packages/core/mesh/messaging/src/signal-manager/memory-signal-manager.ts";
1444
- var MemorySignalManagerContext = class {
1445
- // Swarm messages.
1446
- swarmEvent = new Event3();
1447
- // Mapping from topic to set of peers.
1448
- swarms = new ComplexMap3(PublicKey5.hash);
1449
- // Map of connections for each peer for signaling.
1450
- connections = new ComplexMap3(PeerInfoHash);
1451
- };
1452
- var MemorySignalManager = class {
1453
- _context;
1454
- statusChanged = new Event3();
1455
- swarmEvent = new Event3();
1456
- onMessage = new Event3();
1457
- /** Will be used to emit SwarmEvents on .open() and .close() */
1458
- _joinedSwarms = new ComplexSet3(({ topic, peer }) => topic.toHex() + peer.peerKey);
1459
- _ctx;
1460
- // TODO(dmaretskyi): Replace with callback.
1461
- _freezeTrigger = new Trigger3().wake();
1462
- constructor(_context) {
1463
- this._context = _context;
1464
- this._ctx = new Context3(void 0, {
1465
- F: __dxlog_file5,
1466
- L: 54
1467
- });
1468
- this._ctx.onDispose(this._context.swarmEvent.on((data) => this.swarmEvent.emit(data)));
1469
- }
1470
- async open() {
1471
- if (!this._ctx.disposed) {
1472
- return;
1473
- }
1474
- this._ctx = new Context3(void 0, {
1475
- F: __dxlog_file5,
1476
- L: 63
1477
- });
1478
- this._ctx.onDispose(this._context.swarmEvent.on((data) => this.swarmEvent.emit(data)));
1479
- await Promise.all([
1480
- ...this._joinedSwarms.values()
1481
- ].map((value) => this.join(value)));
1482
- }
1483
- async close() {
1484
- if (this._ctx.disposed) {
1485
- return;
1486
- }
1487
- const joinedSwarmsCopy = new ComplexSet3(({ topic, peer }) => topic.toHex() + peer.peerKey, [
1488
- ...this._joinedSwarms.values()
1489
- ]);
1490
- await Promise.all([
1491
- ...this._joinedSwarms.values()
1492
- ].map((value) => this.leave(value)));
1493
- this._joinedSwarms = joinedSwarmsCopy;
1494
- await this._ctx.dispose();
1495
- }
1496
- getStatus() {
1497
- return [];
1498
- }
1499
- async join({ topic, peer }) {
1500
- invariant4(!this._ctx.disposed, "Closed", {
1501
- F: __dxlog_file5,
1502
- L: 92,
1503
- S: this,
1504
- A: [
1505
- "!this._ctx.disposed",
1506
- "'Closed'"
1507
- ]
1508
- });
1509
- this._joinedSwarms.add({
1510
- topic,
1511
- peer
1512
- });
1513
- if (!this._context.swarms.has(topic)) {
1514
- this._context.swarms.set(topic, new ComplexSet3(PeerInfoHash));
1515
- }
1516
- this._context.swarms.get(topic).add(peer);
1517
- this._context.swarmEvent.emit({
1518
- topic,
1519
- peerAvailable: {
1520
- peer,
1521
- since: /* @__PURE__ */ new Date()
1522
- }
1523
- });
1524
- for (const [topic2, peers] of this._context.swarms) {
1525
- Array.from(peers).forEach((peer2) => {
1526
- this.swarmEvent.emit({
1527
- topic: topic2,
1528
- peerAvailable: {
1529
- peer: peer2,
1530
- since: /* @__PURE__ */ new Date()
1531
- }
1532
- });
1533
- });
1534
- }
1535
- }
1536
- async leave({ topic, peer }) {
1537
- invariant4(!this._ctx.disposed, "Closed", {
1538
- F: __dxlog_file5,
1539
- L: 124,
1540
- S: this,
1541
- A: [
1542
- "!this._ctx.disposed",
1543
- "'Closed'"
1544
- ]
1545
- });
1546
- this._joinedSwarms.delete({
1547
- topic,
1548
- peer
1549
- });
1550
- if (!this._context.swarms.has(topic)) {
1551
- this._context.swarms.set(topic, new ComplexSet3(PeerInfoHash));
1552
- }
1553
- this._context.swarms.get(topic).delete(peer);
1554
- const swarmEvent = {
1555
- topic,
1556
- peerLeft: {
1557
- peer
1558
- }
1559
- };
1560
- this._context.swarmEvent.emit(swarmEvent);
1561
- }
1562
- async query(request) {
1563
- throw new Error("Not implemented");
1564
- }
1565
- async sendMessage({ author, recipient, payload }) {
1566
- log5("send message", {
1567
- author,
1568
- recipient,
1569
- ...dec(payload)
1570
- }, {
1571
- F: __dxlog_file5,
1572
- L: 157,
1573
- S: this,
1574
- C: (f, a) => f(...a)
1575
- });
1576
- invariant4(recipient, void 0, {
1577
- F: __dxlog_file5,
1578
- L: 159,
1579
- S: this,
1580
- A: [
1581
- "recipient",
1582
- ""
1583
- ]
1584
- });
1585
- invariant4(!this._ctx.disposed, "Closed", {
1586
- F: __dxlog_file5,
1587
- L: 160,
1588
- S: this,
1589
- A: [
1590
- "!this._ctx.disposed",
1591
- "'Closed'"
1592
- ]
1593
- });
1594
- await this._freezeTrigger.wait();
1595
- const remote = this._context.connections.get(recipient);
1596
- if (!remote) {
1597
- log5.warn("recipient is not subscribed for messages", {
1598
- author,
1599
- recipient
1600
- }, {
1601
- F: __dxlog_file5,
1602
- L: 166,
1603
- S: this,
1604
- C: (f, a) => f(...a)
1605
- });
1606
- return;
1607
- }
1608
- if (remote._ctx.disposed) {
1609
- log5.warn("recipient is disposed", {
1610
- author,
1611
- recipient
1612
- }, {
1613
- F: __dxlog_file5,
1614
- L: 171,
1615
- S: this,
1616
- C: (f, a) => f(...a)
1617
- });
1618
- return;
1619
- }
1620
- remote._freezeTrigger.wait().then(() => {
1621
- if (remote._ctx.disposed) {
1622
- log5.warn("recipient is disposed", {
1623
- author,
1624
- recipient
1625
- }, {
1626
- F: __dxlog_file5,
1627
- L: 179,
1628
- S: this,
1629
- C: (f, a) => f(...a)
1630
- });
1631
- return;
1632
- }
1633
- log5("receive message", {
1634
- author,
1635
- recipient,
1636
- ...dec(payload)
1637
- }, {
1638
- F: __dxlog_file5,
1639
- L: 183,
1640
- S: this,
1641
- C: (f, a) => f(...a)
1642
- });
1643
- remote.onMessage.emit({
1644
- author,
1645
- recipient,
1646
- payload
1647
- });
1648
- }).catch((err) => {
1649
- log5.error("error while waiting for freeze", {
1650
- err
1651
- }, {
1652
- F: __dxlog_file5,
1653
- L: 188,
1654
- S: this,
1655
- C: (f, a) => f(...a)
1656
- });
1657
- });
1658
- }
1659
- async subscribeMessages(peerInfo) {
1660
- log5("subscribing", {
1661
- peerInfo
1662
- }, {
1663
- F: __dxlog_file5,
1664
- L: 193,
1665
- S: this,
1666
- C: (f, a) => f(...a)
1667
- });
1668
- this._context.connections.set(peerInfo, this);
1669
- }
1670
- async unsubscribeMessages(peerInfo) {
1671
- log5("unsubscribing", {
1672
- peerInfo
1673
- }, {
1674
- F: __dxlog_file5,
1675
- L: 198,
1676
- S: this,
1677
- C: (f, a) => f(...a)
1678
- });
1679
- this._context.connections.delete(peerInfo);
1680
- }
1681
- freeze() {
1682
- this._freezeTrigger.reset();
1683
- }
1684
- unfreeze() {
1685
- this._freezeTrigger.wake();
1686
- }
1687
- };
1688
- var dec = (payload) => {
1689
- if (!payload.type_url.endsWith("ReliablePayload")) {
1690
- return {};
1691
- }
1692
- const relPayload = schema3.getCodecForType("dxos.mesh.messaging.ReliablePayload").decode(payload.value);
1693
- if (typeof relPayload?.payload?.data === "object") {
1694
- return {
1695
- payload: Object.keys(relPayload?.payload?.data)[0],
1696
- sessionId: relPayload?.payload?.sessionId
1697
- };
1698
- }
1699
- return {};
1700
- };
1701
-
1702
- // src/signal-manager/websocket-signal-manager.ts
1703
- import { Event as Event4, sleep as sleep2, synchronized } from "@dxos/async";
1704
- import { LifecycleState, Resource as Resource2 } from "@dxos/context";
1705
- import { invariant as invariant5 } from "@dxos/invariant";
1706
- import { PublicKey as PublicKey6 } from "@dxos/keys";
1707
- import { log as log6 } from "@dxos/log";
1708
- import { RateLimitExceededError, TimeoutError as TimeoutError3, trace as trace8 } from "@dxos/protocols";
1709
- import { BitField, safeAwaitAll as safeAwaitAll2 } from "@dxos/util";
1710
-
1711
- // src/signal-manager/websocket-signal-manager-monitor.ts
1712
- import { trace as trace7 } from "@dxos/tracing";
1713
- var WebsocketSignalManagerMonitor = class {
1714
- recordRateLimitExceeded() {
1715
- trace7.metrics.increment("dxos.mesh.signal.signal-manager.rate-limit-hit", 1);
1716
- }
1717
- recordServerFailure(params) {
1718
- trace7.metrics.increment("dxos.mesh.signal.signal-manager.server-failure", 1, {
1719
- tags: {
1720
- server: params.serverName,
1721
- restarted: params.willRestart
1722
- }
1723
- });
1724
- }
1725
- };
1726
-
1727
- // src/signal-manager/websocket-signal-manager.ts
1728
- function _ts_decorate(decorators, target, key, desc) {
1729
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1730
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1731
- 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;
1732
- return c > 3 && r && Object.defineProperty(target, key, r), r;
1733
- }
1734
- var __dxlog_file6 = "/__w/dxos/dxos/packages/core/mesh/messaging/src/signal-manager/websocket-signal-manager.ts";
1735
- var MAX_SERVER_FAILURES = 5;
1736
- var WSS_SIGNAL_SERVER_REBOOT_DELAY = 3e3;
1737
- var WebsocketSignalManager = class extends Resource2 {
1738
- _hosts;
1739
- _getMetadata;
1740
- _servers = /* @__PURE__ */ new Map();
1741
- _monitor = new WebsocketSignalManagerMonitor();
1742
- /**
1743
- * Used to avoid logging failed server restarts more than once until the server actually recovers.
1744
- */
1745
- _failedServersBitfield;
1746
- failureCount = /* @__PURE__ */ new Map();
1747
- statusChanged = new Event4();
1748
- swarmEvent = new Event4();
1749
- onMessage = new Event4();
1750
- _instanceId = PublicKey6.random().toHex();
1751
- constructor(_hosts, _getMetadata) {
1752
- super(), this._hosts = _hosts, this._getMetadata = _getMetadata;
1753
- log6("Created WebsocketSignalManager", {
1754
- hosts: this._hosts
1755
- }, {
1756
- F: __dxlog_file6,
1757
- L: 59,
1758
- S: this,
1759
- C: (f, a) => f(...a)
1760
- });
1761
- for (const host of this._hosts) {
1762
- if (this._servers.has(host.server)) {
1763
- continue;
1764
- }
1765
- const server = new SignalClient(host.server, this._getMetadata);
1766
- server.swarmEvent.on((data) => this.swarmEvent.emit(data));
1767
- server.onMessage.on((data) => this.onMessage.emit(data));
1768
- server.statusChanged.on(() => this.statusChanged.emit(this.getStatus()));
1769
- this._servers.set(host.server, server);
1770
- this.failureCount.set(host.server, 0);
1771
- }
1772
- this._failedServersBitfield = BitField.zeros(this._hosts.length);
1773
- }
1774
- async _open() {
1775
- log6("open signal manager", {
1776
- hosts: this._hosts
1777
- }, {
1778
- F: __dxlog_file6,
1779
- L: 79,
1780
- S: this,
1781
- C: (f, a) => f(...a)
1782
- });
1783
- log6.trace("dxos.mesh.websocket-signal-manager.open", trace8.begin({
1784
- id: this._instanceId
1785
- }), {
1786
- F: __dxlog_file6,
1787
- L: 80,
1788
- S: this,
1789
- C: (f, a) => f(...a)
1790
- });
1791
- await safeAwaitAll2(this._servers.values(), (server) => server.open());
1792
- log6.trace("dxos.mesh.websocket-signal-manager.open", trace8.end({
1793
- id: this._instanceId
1794
- }), {
1795
- F: __dxlog_file6,
1796
- L: 84,
1797
- S: this,
1798
- C: (f, a) => f(...a)
1799
- });
1800
- }
1801
- async _close() {
1802
- await safeAwaitAll2(this._servers.values(), (server) => server.close());
1803
- }
1804
- async restartServer(serverName) {
1805
- log6("restarting server", {
1806
- serverName
1807
- }, {
1808
- F: __dxlog_file6,
1809
- L: 92,
1810
- S: this,
1811
- C: (f, a) => f(...a)
1812
- });
1813
- invariant5(this._lifecycleState === LifecycleState.OPEN, void 0, {
1814
- F: __dxlog_file6,
1815
- L: 93,
1816
- S: this,
1817
- A: [
1818
- "this._lifecycleState === LifecycleState.OPEN",
1819
- ""
1820
- ]
1821
- });
1822
- const server = this._servers.get(serverName);
1823
- invariant5(server, "server not found", {
1824
- F: __dxlog_file6,
1825
- L: 96,
1826
- S: this,
1827
- A: [
1828
- "server",
1829
- "'server not found'"
1830
- ]
1831
- });
1832
- await server.close();
1833
- await sleep2(WSS_SIGNAL_SERVER_REBOOT_DELAY);
1834
- await server.open();
1835
- }
1836
- getStatus() {
1837
- return Array.from(this._servers.values()).map((server) => server.getStatus());
1838
- }
1839
- async join({ topic, peer }) {
1840
- log6("join", {
1841
- topic,
1842
- peer
1843
- }, {
1844
- F: __dxlog_file6,
1845
- L: 109,
1846
- S: this,
1847
- C: (f, a) => f(...a)
1848
- });
1849
- invariant5(this._lifecycleState === LifecycleState.OPEN, void 0, {
1850
- F: __dxlog_file6,
1851
- L: 110,
1852
- S: this,
1853
- A: [
1854
- "this._lifecycleState === LifecycleState.OPEN",
1855
- ""
1856
- ]
1857
- });
1858
- await this._forEachServer((server) => server.join({
1859
- topic,
1860
- peer
1861
- }));
1862
- }
1863
- async leave({ topic, peer }) {
1864
- log6("leaving", {
1865
- topic,
1866
- peer
1867
- }, {
1868
- F: __dxlog_file6,
1869
- L: 116,
1870
- S: this,
1871
- C: (f, a) => f(...a)
1872
- });
1873
- invariant5(this._lifecycleState === LifecycleState.OPEN, void 0, {
1874
- F: __dxlog_file6,
1875
- L: 117,
1876
- S: this,
1877
- A: [
1878
- "this._lifecycleState === LifecycleState.OPEN",
1879
- ""
1880
- ]
1881
- });
1882
- await this._forEachServer((server) => server.leave({
1883
- topic,
1884
- peer
1885
- }));
1886
- }
1887
- async query({ topic }) {
1888
- throw new Error("Not implemented");
1889
- }
1890
- async sendMessage({ author, recipient, payload }) {
1891
- log6("signal", {
1892
- recipient
1893
- }, {
1894
- F: __dxlog_file6,
1895
- L: 126,
1896
- S: this,
1897
- C: (f, a) => f(...a)
1898
- });
1899
- invariant5(this._lifecycleState === LifecycleState.OPEN, void 0, {
1900
- F: __dxlog_file6,
1901
- L: 127,
1902
- S: this,
1903
- A: [
1904
- "this._lifecycleState === LifecycleState.OPEN",
1905
- ""
1906
- ]
1907
- });
1908
- void this._forEachServer(async (server, serverName, index) => {
1909
- void server.sendMessage({
1910
- author,
1911
- recipient,
1912
- payload
1913
- }).then(() => this._clearServerFailedFlag(serverName, index)).catch((err) => {
1914
- if (err instanceof RateLimitExceededError) {
1915
- log6.info("WSS rate limit exceeded", {
1916
- err
1917
- }, {
1918
- F: __dxlog_file6,
1919
- L: 135,
1920
- S: this,
1921
- C: (f, a) => f(...a)
1922
- });
1923
- this._monitor.recordRateLimitExceeded();
1924
- } else if (err instanceof TimeoutError3 || err.constructor.name === "TimeoutError") {
1925
- log6.info("WSS sendMessage timeout", {
1926
- err
1927
- }, {
1928
- F: __dxlog_file6,
1929
- L: 138,
1930
- S: this,
1931
- C: (f, a) => f(...a)
1932
- });
1933
- void this.checkServerFailure(serverName, index);
1934
- } else {
1935
- log6.warn(`error sending to ${serverName}`, {
1936
- err
1937
- }, {
1938
- F: __dxlog_file6,
1939
- L: 141,
1940
- S: this,
1941
- C: (f, a) => f(...a)
1942
- });
1943
- void this.checkServerFailure(serverName, index);
1944
- }
1945
- });
1946
- });
1947
- }
1948
- async checkServerFailure(serverName, index) {
1949
- const failureCount = this.failureCount.get(serverName) ?? 0;
1950
- const isRestartRequired = failureCount > MAX_SERVER_FAILURES;
1951
- this._monitor.recordServerFailure({
1952
- serverName,
1953
- willRestart: isRestartRequired
1954
- });
1955
- if (isRestartRequired) {
1956
- if (!BitField.get(this._failedServersBitfield, index)) {
1957
- log6.warn("too many failures for ws-server, restarting", {
1958
- serverName,
1959
- failureCount
1960
- }, {
1961
- F: __dxlog_file6,
1962
- L: 155,
1963
- S: this,
1964
- C: (f, a) => f(...a)
1965
- });
1966
- BitField.set(this._failedServersBitfield, index, true);
1967
- }
1968
- await this.restartServer(serverName);
1969
- this.failureCount.set(serverName, 0);
1970
- return;
1971
- }
1972
- this.failureCount.set(serverName, (this.failureCount.get(serverName) ?? 0) + 1);
1973
- }
1974
- _clearServerFailedFlag(serverName, index) {
1975
- if (BitField.get(this._failedServersBitfield, index)) {
1976
- log6.info("server connection restored", {
1977
- serverName
1978
- }, {
1979
- F: __dxlog_file6,
1980
- L: 168,
1981
- S: this,
1982
- C: (f, a) => f(...a)
1983
- });
1984
- BitField.set(this._failedServersBitfield, index, false);
1985
- this.failureCount.set(serverName, 0);
1986
- }
1987
- }
1988
- async subscribeMessages(peer) {
1989
- log6("subscribed for message stream", {
1990
- peer
1991
- }, {
1992
- F: __dxlog_file6,
1993
- L: 175,
1994
- S: this,
1995
- C: (f, a) => f(...a)
1996
- });
1997
- invariant5(this._lifecycleState === LifecycleState.OPEN, void 0, {
1998
- F: __dxlog_file6,
1999
- L: 176,
2000
- S: this,
2001
- A: [
2002
- "this._lifecycleState === LifecycleState.OPEN",
2003
- ""
2004
- ]
2005
- });
2006
- await this._forEachServer(async (server) => server.subscribeMessages(peer));
2007
- }
2008
- async unsubscribeMessages(peer) {
2009
- log6("subscribed for message stream", {
2010
- peer
2011
- }, {
2012
- F: __dxlog_file6,
2013
- L: 182,
2014
- S: this,
2015
- C: (f, a) => f(...a)
2016
- });
2017
- invariant5(this._lifecycleState === LifecycleState.OPEN, void 0, {
2018
- F: __dxlog_file6,
2019
- L: 183,
2020
- S: this,
2021
- A: [
2022
- "this._lifecycleState === LifecycleState.OPEN",
2023
- ""
2024
- ]
2025
- });
2026
- await this._forEachServer(async (server) => server.unsubscribeMessages(peer));
2027
- }
2028
- async _forEachServer(fn) {
2029
- return Promise.all(Array.from(this._servers.entries()).map(([serverName, server], idx) => fn(server, serverName, idx)));
2030
- }
2031
- };
2032
- _ts_decorate([
2033
- synchronized
2034
- ], WebsocketSignalManager.prototype, "join", null);
2035
- _ts_decorate([
2036
- synchronized
2037
- ], WebsocketSignalManager.prototype, "leave", null);
2038
- _ts_decorate([
2039
- synchronized
2040
- ], WebsocketSignalManager.prototype, "checkServerFailure", null);
2041
-
2042
- // src/signal-manager/edge-signal-manager.ts
2043
- import { Event as Event5, scheduleMicroTask } from "@dxos/async";
2044
- import { Resource as Resource3, cancelWithContext as cancelWithContext3 } from "@dxos/context";
2045
- import { EdgeIdentityChangedError, protocol } from "@dxos/edge-client";
2046
- import { invariant as invariant6 } from "@dxos/invariant";
2047
- import { PublicKey as PublicKey7 } from "@dxos/keys";
2048
- import { log as log7 } from "@dxos/log";
2049
- import { EdgeService } from "@dxos/protocols";
2050
- import { bufWkt } from "@dxos/protocols/buf";
2051
- import { SwarmRequest_Action as SwarmRequestAction, SwarmRequestSchema, SwarmResponseSchema } from "@dxos/protocols/buf/dxos/edge/messenger_pb";
2052
- import { ComplexMap as ComplexMap4, ComplexSet as ComplexSet4 } from "@dxos/util";
2053
- var __dxlog_file7 = "/__w/dxos/dxos/packages/core/mesh/messaging/src/signal-manager/edge-signal-manager.ts";
2054
- var EdgeSignalManager = class extends Resource3 {
2055
- /**
2056
- * @deprecated
2057
- */
2058
- swarmEvent = new Event5();
2059
- swarmState = new Event5();
2060
- onMessage = new Event5();
2061
- /**
2062
- * Swarm key -> { peer: <own state payload>, joinedPeers: <state of swarm> }.
2063
- */
2064
- // TODO(mykola): This class should not contain swarm state joinedPeers. Temporary before network-manager API changes to accept list of peers.
2065
- _swarmPeers = new ComplexMap4(PublicKey7.hash);
2066
- _edgeConnection;
2067
- constructor({ edgeConnection }) {
2068
- super();
2069
- this._edgeConnection = edgeConnection;
2070
- }
2071
- async _open() {
2072
- this._ctx.onDispose(this._edgeConnection.onMessage((message) => this._onMessage(message)));
2073
- this._ctx.onDispose(this._edgeConnection.onReconnected(() => {
2074
- scheduleMicroTask(this._ctx, () => this._rejoinAllSwarms());
2075
- }));
2076
- }
2077
- /**
2078
- * Warning: PeerInfo is inferred from edgeConnection.
2079
- */
2080
- async join({ topic, peer }) {
2081
- if (!this._matchSelfPeerInfo(peer)) {
2082
- log7.warn("ignoring peer info on join request", {
2083
- peer,
2084
- expected: {
2085
- peerKey: this._edgeConnection.peerKey,
2086
- identityKey: this._edgeConnection.identityKey
2087
- }
2088
- }, {
2089
- F: __dxlog_file7,
2090
- L: 66,
2091
- S: this,
2092
- C: (f, a) => f(...a)
2093
- });
2094
- peer.identityKey = this._edgeConnection.identityKey;
2095
- peer.peerKey = this._edgeConnection.peerKey;
2096
- }
2097
- this._swarmPeers.set(topic, {
2098
- lastState: peer.state,
2099
- joinedPeers: new ComplexSet4(PeerInfoHash)
2100
- });
2101
- await this._edgeConnection.send(protocol.createMessage(SwarmRequestSchema, {
2102
- serviceId: EdgeService.SWARM,
2103
- source: createMessageSource(topic, peer),
2104
- payload: {
2105
- action: SwarmRequestAction.JOIN,
2106
- swarmKeys: [
2107
- topic.toHex()
2108
- ]
2109
- }
2110
- }));
2111
- }
2112
- async leave({ topic, peer }) {
2113
- this._swarmPeers.delete(topic);
2114
- try {
2115
- await this._edgeConnection.send(protocol.createMessage(SwarmRequestSchema, {
2116
- serviceId: EdgeService.SWARM,
2117
- source: createMessageSource(topic, peer),
2118
- payload: {
2119
- action: SwarmRequestAction.LEAVE,
2120
- swarmKeys: [
2121
- topic.toHex()
2122
- ]
2123
- }
2124
- }));
2125
- } catch (err) {
2126
- if (err instanceof EdgeIdentityChangedError) {
2127
- return;
2128
- }
2129
- throw err;
2130
- }
2131
- }
2132
- async query({ topic }) {
2133
- const response = cancelWithContext3(this._ctx, this.swarmState.waitFor((state) => state.swarmKey === topic.toHex()));
2134
- await this._edgeConnection.send(protocol.createMessage(SwarmRequestSchema, {
2135
- serviceId: EdgeService.SWARM,
2136
- source: createMessageSource(topic, {
2137
- peerKey: this._edgeConnection.peerKey,
2138
- identityKey: this._edgeConnection.identityKey
2139
- }),
2140
- payload: {
2141
- action: SwarmRequestAction.INFO,
2142
- swarmKeys: [
2143
- topic.toHex()
2144
- ]
2145
- }
2146
- }));
2147
- return response;
2148
- }
2149
- async sendMessage(message) {
2150
- if (!this._matchSelfPeerInfo(message.author)) {
2151
- log7.warn("ignoring author on send request", {
2152
- author: message.author,
2153
- expected: {
2154
- peerKey: this._edgeConnection.peerKey,
2155
- identityKey: this._edgeConnection.identityKey
2156
- }
2157
- }, {
2158
- F: __dxlog_file7,
2159
- L: 131,
2160
- S: this,
2161
- C: (f, a) => f(...a)
2162
- });
2163
- }
2164
- await this._edgeConnection.send(protocol.createMessage(bufWkt.AnySchema, {
2165
- serviceId: EdgeService.SIGNAL,
2166
- source: message.author,
2167
- target: [
2168
- message.recipient
2169
- ],
2170
- payload: {
2171
- typeUrl: message.payload.type_url,
2172
- value: message.payload.value
2173
- }
2174
- }));
2175
- }
2176
- async subscribeMessages(peerInfo) {
2177
- }
2178
- async unsubscribeMessages(peerInfo) {
2179
- }
2180
- _onMessage(message) {
2181
- switch (message.serviceId) {
2182
- case EdgeService.SWARM: {
2183
- this._processSwarmResponse(message);
2184
- break;
2185
- }
2186
- case EdgeService.SIGNAL: {
2187
- this._processMessage(message);
2188
- }
2189
- }
2190
- }
2191
- _processSwarmResponse(message) {
2192
- invariant6(protocol.getPayloadType(message) === SwarmResponseSchema.typeName, "Wrong payload type", {
2193
- F: __dxlog_file7,
2194
- L: 168,
2195
- S: this,
2196
- A: [
2197
- "protocol.getPayloadType(message) === SwarmResponseSchema.typeName",
2198
- "'Wrong payload type'"
2199
- ]
2200
- });
2201
- const payload = protocol.getPayload(message, SwarmResponseSchema);
2202
- this.swarmState.emit(payload);
2203
- const topic = PublicKey7.from(payload.swarmKey);
2204
- if (!this._swarmPeers.has(topic)) {
2205
- return;
2206
- }
2207
- const { joinedPeers: oldPeers } = this._swarmPeers.get(topic);
2208
- const timestamp = message.timestamp ? new Date(Date.parse(message.timestamp)) : /* @__PURE__ */ new Date();
2209
- const newPeers = new ComplexSet4(PeerInfoHash, payload.peers);
2210
- for (const peer of newPeers) {
2211
- if (oldPeers.has(peer)) {
2212
- continue;
2213
- }
2214
- this.swarmEvent.emit({
2215
- topic,
2216
- peerAvailable: {
2217
- peer,
2218
- since: timestamp
2219
- }
2220
- });
2221
- }
2222
- for (const peer of oldPeers) {
2223
- if (newPeers.has(peer)) {
2224
- continue;
2225
- }
2226
- this.swarmEvent.emit({
2227
- topic,
2228
- peerLeft: {
2229
- peer
2230
- }
2231
- });
2232
- }
2233
- this._swarmPeers.get(topic).joinedPeers = newPeers;
2234
- }
2235
- _processMessage(message) {
2236
- invariant6(protocol.getPayloadType(message) === bufWkt.AnySchema.typeName, "Wrong payload type", {
2237
- F: __dxlog_file7,
2238
- L: 206,
2239
- S: this,
2240
- A: [
2241
- "protocol.getPayloadType(message) === bufWkt.AnySchema.typeName",
2242
- "'Wrong payload type'"
2243
- ]
2244
- });
2245
- const payload = protocol.getPayload(message, bufWkt.AnySchema);
2246
- invariant6(message.source, "source is missing", {
2247
- F: __dxlog_file7,
2248
- L: 208,
2249
- S: this,
2250
- A: [
2251
- "message.source",
2252
- "'source is missing'"
2253
- ]
2254
- });
2255
- invariant6(message.target, "target is missing", {
2256
- F: __dxlog_file7,
2257
- L: 209,
2258
- S: this,
2259
- A: [
2260
- "message.target",
2261
- "'target is missing'"
2262
- ]
2263
- });
2264
- invariant6(message.target.length === 1, "target should have exactly one item", {
2265
- F: __dxlog_file7,
2266
- L: 210,
2267
- S: this,
2268
- A: [
2269
- "message.target.length === 1",
2270
- "'target should have exactly one item'"
2271
- ]
2272
- });
2273
- this.onMessage.emit({
2274
- author: message.source,
2275
- recipient: message.target[0],
2276
- payload: {
2277
- type_url: payload.typeUrl,
2278
- value: payload.value
2279
- }
2280
- });
2281
- }
2282
- _matchSelfPeerInfo(peer) {
2283
- return peer && (peer.peerKey === this._edgeConnection.peerKey || peer.identityKey === this._edgeConnection.identityKey);
2284
- }
2285
- async _rejoinAllSwarms() {
2286
- log7("rejoin swarms", {
2287
- swarms: Array.from(this._swarmPeers.keys())
2288
- }, {
2289
- F: __dxlog_file7,
2290
- L: 229,
2291
- S: this,
2292
- C: (f, a) => f(...a)
2293
- });
2294
- for (const [topic, { lastState }] of this._swarmPeers.entries()) {
2295
- await this.join({
2296
- topic,
2297
- peer: {
2298
- peerKey: this._edgeConnection.peerKey,
2299
- identityKey: this._edgeConnection.identityKey,
2300
- state: lastState
2301
- }
2302
- });
2303
- }
2304
- }
2305
- };
2306
- var createMessageSource = (topic, peerInfo) => {
2307
- return {
2308
- swarmKey: topic.toHex(),
2309
- ...peerInfo
2310
- };
2311
- };
2312
-
2313
- // src/signal-manager/utils.ts
2314
- import { invariant as invariant7 } from "@dxos/invariant";
2315
- import { log as log8 } from "@dxos/log";
2316
- import { DeviceKind } from "@dxos/protocols/proto/dxos/client/services";
2317
- var __dxlog_file8 = "/__w/dxos/dxos/packages/core/mesh/messaging/src/signal-manager/utils.ts";
2318
- var setIdentityTags = ({ identityService, devicesService, setTag }) => {
2319
- identityService.queryIdentity().subscribe((idqr) => {
2320
- if (!idqr?.identity?.identityKey) {
2321
- log8("empty response from identity service", {
2322
- idqr
2323
- }, {
2324
- F: __dxlog_file8,
2325
- L: 21,
2326
- S: void 0,
2327
- C: (f, a) => f(...a)
2328
- });
2329
- return;
2330
- }
2331
- setTag("identityKey", idqr.identity.identityKey.truncate());
2332
- });
2333
- devicesService.queryDevices().subscribe((dqr) => {
2334
- if (!dqr || !dqr.devices || dqr.devices.length === 0) {
2335
- log8("empty response from device service", {
2336
- device: dqr
2337
- }, {
2338
- F: __dxlog_file8,
2339
- L: 30,
2340
- S: void 0,
2341
- C: (f, a) => f(...a)
2342
- });
2343
- return;
2344
- }
2345
- invariant7(dqr, "empty response from device service", {
2346
- F: __dxlog_file8,
2347
- L: 33,
2348
- S: void 0,
2349
- A: [
2350
- "dqr",
2351
- "'empty response from device service'"
2352
- ]
2353
- });
2354
- const thisDevice = dqr.devices.find((device) => device.kind === DeviceKind.CURRENT);
2355
- if (!thisDevice) {
2356
- log8("no current device", {
2357
- device: dqr
2358
- }, {
2359
- F: __dxlog_file8,
2360
- L: 37,
2361
- S: void 0,
2362
- C: (f, a) => f(...a)
2363
- });
2364
- return;
2365
- }
2366
- setTag("deviceKey", thisDevice.deviceKey.truncate());
2367
- });
2368
- };
2369
-
2370
- export {
2371
- Messenger,
2372
- SignalClient,
2373
- PeerInfoHash,
2374
- MemorySignalManagerContext,
2375
- MemorySignalManager,
2376
- WebsocketSignalManager,
2377
- EdgeSignalManager,
2378
- setIdentityTags
2379
- };
2380
- //# sourceMappingURL=chunk-PVWR5V42.mjs.map