@dxos/teleport 0.1.52 → 0.1.53-main.032dce6

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.
@@ -104,11 +104,13 @@ var encodeFrame = (payload) => {
104
104
  // packages/core/mesh/teleport/src/muxing/muxer.ts
105
105
  import assert2 from "@dxos/node-std/assert";
106
106
  import { Duplex as Duplex2 } from "@dxos/node-std/stream";
107
- import { Event } from "@dxos/async";
107
+ import { DeferredTask, Event, sleep } from "@dxos/async";
108
+ import { Context } from "@dxos/context";
108
109
  import { failUndefined } from "@dxos/debug";
109
110
  import { log } from "@dxos/log";
110
111
  import { schema } from "@dxos/protocols";
111
112
  var codec = schema.getCodecForType("dxos.mesh.muxer.Command");
113
+ var DEBOUNCE_STATS_INTERVAL = 1e3;
112
114
  var Muxer = class {
113
115
  constructor() {
114
116
  this._framer = new Framer();
@@ -119,6 +121,20 @@ var Muxer = class {
119
121
  this._destroyed = false;
120
122
  this._destroying = false;
121
123
  this.close = new Event();
124
+ this.statsUpdated = new Event();
125
+ this._ctx = new Context();
126
+ this._emitStats = new DeferredTask(this._ctx, async () => {
127
+ if (this._destroyed || this._destroying) {
128
+ return;
129
+ }
130
+ this.statsUpdated.emit(Array.from(this._channelsByTag.values()).map((channel) => ({
131
+ id: channel.id,
132
+ tag: channel.tag,
133
+ bytesSent: channel.stats.bytesSent,
134
+ bytesReceived: channel.stats.bytesReceived
135
+ })));
136
+ await sleep(DEBOUNCE_STATS_INTERVAL);
137
+ });
122
138
  this._framer.port.subscribe((msg) => {
123
139
  this._handleCommand(codec.decode(msg));
124
140
  });
@@ -144,6 +160,8 @@ var Muxer = class {
144
160
  }
145
161
  });
146
162
  channel.push = (data) => {
163
+ channel.stats.bytesReceived += data.length;
164
+ this._emitStats.schedule();
147
165
  stream.push(data);
148
166
  };
149
167
  channel.destroy = (err) => {
@@ -173,6 +191,8 @@ var Muxer = class {
173
191
  let inboundBuffer = [];
174
192
  let callback;
175
193
  channel.push = (data) => {
194
+ channel.stats.bytesReceived += data.length;
195
+ this._emitStats.schedule();
176
196
  if (callback) {
177
197
  callback(data);
178
198
  } else {
@@ -229,6 +249,7 @@ var Muxer = class {
229
249
  this.close.emit(err);
230
250
  this._channelsByLocalId.clear();
231
251
  this._channelsByTag.clear();
252
+ void this._ctx.dispose();
232
253
  }
233
254
  _handleCommand(cmd) {
234
255
  var _a;
@@ -236,14 +257,14 @@ var Muxer = class {
236
257
  cmd
237
258
  }, {
238
259
  file: "muxer.ts",
239
- line: 194,
260
+ line: 224,
240
261
  scope: this,
241
262
  callSite: (f, a) => f(...a)
242
263
  });
243
264
  if (this._destroyed || this._destroying) {
244
265
  log.warn("Received command after destroy", {}, {
245
266
  file: "muxer.ts",
246
- line: 197,
267
+ line: 227,
247
268
  scope: this,
248
269
  callSite: (f, a) => f(...a)
249
270
  });
@@ -271,7 +292,7 @@ var Muxer = class {
271
292
  tag: stream.tag
272
293
  }, {
273
294
  file: "muxer.ts",
274
- line: 221,
295
+ line: 251,
275
296
  scope: this,
276
297
  callSite: (f, a) => f(...a)
277
298
  });
@@ -297,7 +318,11 @@ var Muxer = class {
297
318
  contentType: params.contentType,
298
319
  buffer: [],
299
320
  push: null,
300
- destroy: null
321
+ destroy: null,
322
+ stats: {
323
+ bytesSent: 0,
324
+ bytesReceived: 0
325
+ }
301
326
  };
302
327
  this._channelsByTag.set(channel.tag, channel);
303
328
  this._channelsByLocalId.set(channel.id, channel);
@@ -305,6 +330,8 @@ var Muxer = class {
305
330
  return channel;
306
331
  }
307
332
  _sendData(channel, data) {
333
+ channel.stats.bytesSent += data.length;
334
+ this._emitStats.schedule();
308
335
  if (channel.remoteId === null) {
309
336
  channel.buffer.push(data);
310
337
  } else {
@@ -321,7 +348,7 @@ var Muxer = class {
321
348
  // packages/core/mesh/teleport/src/teleport.ts
322
349
  import assert3 from "@dxos/node-std/assert";
323
350
  import { asyncTimeout, scheduleTaskInterval, runInContextAsync, synchronized, scheduleTask } from "@dxos/async";
324
- import { Context } from "@dxos/context";
351
+ import { Context as Context2 } from "@dxos/context";
325
352
  import { failUndefined as failUndefined2 } from "@dxos/debug";
326
353
  import { PublicKey } from "@dxos/keys";
327
354
  import { log as log2 } from "@dxos/log";
@@ -340,12 +367,12 @@ var __decorate = function(decorators, target, key, desc) {
340
367
  };
341
368
  var Teleport = class {
342
369
  constructor({ initiator, localPeerId, remotePeerId }) {
343
- this._ctx = new Context({
370
+ this._ctx = new Context2({
344
371
  onError: (err) => {
345
372
  void this.destroy(err).catch(() => {
346
373
  log2.error("Error during destroy", err, {
347
374
  file: "teleport.ts",
348
- line: 34,
375
+ line: 35,
349
376
  scope: this,
350
377
  callSite: (f, a) => f(...a)
351
378
  });
@@ -359,7 +386,7 @@ var Teleport = class {
359
386
  onTimeout: () => {
360
387
  this.destroy(new Error("Connection timed out")).catch((err) => log2.catch(err, {}, {
361
388
  file: "teleport.ts",
362
- line: 45,
389
+ line: 46,
363
390
  scope: this,
364
391
  callSite: (f, a) => f(...a)
365
392
  }));
@@ -380,7 +407,7 @@ var Teleport = class {
380
407
  name
381
408
  }, {
382
409
  file: "teleport.ts",
383
- line: 64,
410
+ line: 65,
384
411
  scope: this,
385
412
  callSite: (f, a) => f(...a)
386
413
  });
@@ -406,6 +433,9 @@ var Teleport = class {
406
433
  get stream() {
407
434
  return this._muxer.stream;
408
435
  }
436
+ get stats() {
437
+ return this._muxer.statsUpdated;
438
+ }
409
439
  /**
410
440
  * Blocks until the handshake is complete.
411
441
  */
@@ -428,7 +458,7 @@ var Teleport = class {
428
458
  } catch (err1) {
429
459
  log2.catch(err1, {}, {
430
460
  file: "teleport.ts",
431
- line: 120,
461
+ line: 125,
432
462
  scope: this,
433
463
  callSite: (f, a) => f(...a)
434
464
  });
@@ -444,7 +474,7 @@ var Teleport = class {
444
474
  name
445
475
  }, {
446
476
  file: "teleport.ts",
447
- line: 132,
477
+ line: 137,
448
478
  scope: this,
449
479
  callSite: (f, a) => f(...a)
450
480
  });
@@ -476,7 +506,7 @@ var Teleport = class {
476
506
  extensionName
477
507
  }, {
478
508
  file: "teleport.ts",
479
- line: 162,
509
+ line: 167,
480
510
  scope: this,
481
511
  callSite: (f, a) => f(...a)
482
512
  });
@@ -504,7 +534,7 @@ var Teleport = class {
504
534
  extensionName
505
535
  }, {
506
536
  file: "teleport.ts",
507
- line: 185,
537
+ line: 190,
508
538
  scope: this,
509
539
  callSite: (f, a) => f(...a)
510
540
  });
@@ -516,7 +546,7 @@ __decorate([
516
546
  var ControlExtension = class {
517
547
  constructor(opts) {
518
548
  this.opts = opts;
519
- this._ctx = new Context({
549
+ this._ctx = new Context2({
520
550
  onError: (err) => {
521
551
  this._extensionContext.close(err);
522
552
  }
@@ -660,4 +690,4 @@ export {
660
690
  Teleport,
661
691
  TestExtension
662
692
  };
663
- //# sourceMappingURL=chunk-NJQ5JWQJ.mjs.map
693
+ //# sourceMappingURL=chunk-XWWASTDK.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/muxing/framer.ts", "../../../src/muxing/muxer.ts", "../../../src/teleport.ts", "../../../src/testing/test-extension.ts"],
4
+ "sourcesContent": ["//\n// Copyright 2022 DXOS.org\n//\n\nimport assert from 'node:assert';\nimport { Duplex } from 'node:stream';\nimport * as varint from 'varint';\n\nimport { RpcPort } from './rpc-port';\n\n/**\n * Framer that turns a stream of binary messages into a framed RpcPort.\n *\n * Buffers are written prefixed by their length encoded as a varint.\n */\nexport class Framer {\n // private readonly _tagBuffer = Buffer.alloc(4)\n private _messageCb?: (msg: Uint8Array) => void;\n private _subscribeCb?: () => void;\n private _buffer?: Buffer; // The rest of the bytes from the previous write call.\n\n private readonly _stream = new Duplex({\n objectMode: false,\n read: () => {},\n write: (chunk, encoding, callback) => {\n assert(!this._subscribeCb, 'Internal Framer bug. Concurrent writes detected.');\n\n if (this._buffer && this._buffer.length > 0) {\n this._buffer = Buffer.concat([this._buffer, chunk]);\n } else {\n this._buffer = chunk;\n }\n\n if (this._messageCb) {\n this._popFrames();\n callback();\n } else {\n this._subscribeCb = () => {\n // Schedule the processing of the chunk after the peer subscribes to the messages.\n this._popFrames();\n this._subscribeCb = undefined;\n callback();\n };\n }\n },\n });\n\n public readonly port: RpcPort = {\n send: (message) => {\n // log('write', { len: message.length, frame: Buffer.from(message).toString('hex') })\n this._stream.push(encodeFrame(message));\n },\n subscribe: (callback) => {\n assert(!this._messageCb, 'Rpc port already has a message listener.');\n this._messageCb = callback;\n this._subscribeCb?.();\n return () => {\n this._messageCb = undefined;\n };\n },\n };\n\n get stream(): Duplex {\n return this._stream;\n }\n\n /**\n * Attempts to pop frames from the buffer and call the message callback.\n */\n private _popFrames() {\n let offset = 0;\n while (offset < this._buffer!.length) {\n const frame = decodeFrame(this._buffer!, offset);\n\n if (!frame) {\n break; // Couldn't read frame but there are still bytes left in the buffer.\n }\n offset += frame.bytesConsumed;\n // TODO(dmaretskyi): Possible bug if the peer unsubscribes while we're reading frames.\n // log('read', { len: frame.payload.length, frame: Buffer.from(frame.payload).toString('hex') })\n this._messageCb!(frame.payload);\n }\n\n if (offset < this._buffer!.length) {\n // Save the rest of the bytes for the next write call.\n this._buffer = this._buffer!.subarray(offset);\n } else {\n this._buffer = undefined;\n }\n }\n\n destroy() {\n // TODO(dmaretskyi): Call stream.end() instead?\n this._stream.destroy();\n }\n}\n\n/**\n * Attempts to read a frame from the input buffer.\n */\nexport const decodeFrame = (buffer: Buffer, offset: number): { payload: Buffer; bytesConsumed: number } | undefined => {\n try {\n const frameLength = varint.decode(buffer, offset);\n const tagLength = varint.decode.bytes;\n\n if (buffer.length < offset + tagLength + frameLength) {\n // Not enough bytes to read the frame.\n return undefined;\n }\n\n const payload = buffer.subarray(offset + tagLength, offset + tagLength + frameLength);\n\n return {\n payload,\n bytesConsumed: tagLength + frameLength,\n };\n } catch (err) {\n if (err instanceof RangeError) {\n // Not enough bytes to read the tag.\n return undefined;\n } else {\n throw err;\n }\n }\n};\n\nexport const encodeFrame = (payload: Uint8Array): Buffer => {\n const tagLength = varint.encodingLength(payload.length);\n const frame = Buffer.allocUnsafe(tagLength + payload.length);\n varint.encode(payload.length, frame);\n frame.set(payload, tagLength);\n return frame;\n};\n", "//\n// Copyright 2022 DXOS.org\n//\n\nimport assert from 'node:assert';\nimport { Duplex } from 'node:stream';\n\nimport { DeferredTask, Event, sleep } from '@dxos/async';\nimport { Context } from '@dxos/context';\nimport { failUndefined } from '@dxos/debug';\nimport { log } from '@dxos/log';\nimport { schema } from '@dxos/protocols';\nimport { ConnectionInfo } from '@dxos/protocols/proto/dxos/devtools/swarm';\nimport { Command } from '@dxos/protocols/proto/dxos/mesh/muxer';\n\nimport { Framer } from './framer';\nimport { RpcPort } from './rpc-port';\n\nconst codec = schema.getCodecForType('dxos.mesh.muxer.Command');\n\nexport type CleanupCb = void | (() => void);\n\nexport type CreateChannelOpts = {\n /**\n * MIME type of the wire content.\n *\n * Examples:\n * - application/octet-stream\n * - application/x-protobuf; messageType=\"dxos.rpc.Message\"\n */\n contentType?: string;\n};\n\nconst DEBOUNCE_STATS_INTERVAL = 1000;\n\n/**\n * Channel based multiplexer.\n *\n * Can be used to open a number of channels represented by streams or RPC ports.\n * Performs framing for RPC ports.\n * Will buffer data until the remote peer opens the channel.\n *\n * The API will not advertise channels that as they are opened by the remote peer.\n * A higher level API (could be build on top of this muxer) for channel discovery is required.\n */\nexport class Muxer {\n private readonly _framer = new Framer();\n public readonly stream = this._framer.stream;\n\n private readonly _channelsByLocalId = new Map<number, Channel>();\n private readonly _channelsByTag = new Map<string, Channel>();\n\n private _nextId = 0;\n private _destroyed = false;\n private _destroying = false;\n\n public close = new Event<Error | undefined>();\n\n public statsUpdated = new Event<ConnectionInfo.StreamStats[]>();\n\n private readonly _ctx = new Context();\n private readonly _emitStats = new DeferredTask(this._ctx, async () => {\n if (this._destroyed || this._destroying) {\n return;\n }\n\n this.statsUpdated.emit(\n Array.from(this._channelsByTag.values()).map((channel) => ({\n id: channel.id,\n tag: channel.tag,\n bytesSent: channel.stats.bytesSent,\n bytesReceived: channel.stats.bytesReceived,\n })),\n );\n\n await sleep(DEBOUNCE_STATS_INTERVAL);\n });\n\n constructor() {\n this._framer.port.subscribe((msg) => {\n this._handleCommand(codec.decode(msg));\n });\n }\n\n /**\n * Creates a duplex Node.js-style stream.\n * The remote peer is expected to call `createStream` with the same tag.\n * The stream is immediately readable and writable.\n * NOTE: The data will be buffered until the stream is opened remotely with the same tag (may cause a memory leak).\n */\n createStream(tag: string, opts: CreateChannelOpts = {}): Duplex {\n const channel = this._getOrCreateStream({\n tag,\n contentType: opts.contentType,\n });\n assert(!channel.push, `Channel already open: ${tag}`);\n\n const stream = new Duplex({\n write: (data, encoding, callback) => {\n this._sendData(channel, data);\n // TODO(dmaretskyi): Should we error if sending data has errored?\n callback();\n },\n read: () => {}, // No-op. We will push data when we receive it.\n });\n\n channel.push = (data) => {\n channel.stats.bytesReceived += data.length;\n this._emitStats.schedule();\n stream.push(data);\n };\n channel.destroy = (err) => {\n // TODO(dmaretskyi): Call stream.end() instead?\n stream.destroy(err);\n };\n\n // NOTE: Make sure channel.push is set before sending the command.\n this._sendCommand({\n openChannel: {\n id: channel.id,\n tag: channel.tag,\n contentType: channel.contentType,\n },\n });\n\n return stream;\n }\n\n /**\n * Creates an RPC port.\n * The remote peer is expected to call `createPort` with the same tag.\n * The port is immediately usable.\n * NOTE: The data will be buffered until the stream is opened remotely with the same tag (may cause a memory leak).\n */\n createPort(tag: string, opts: CreateChannelOpts = {}): RpcPort {\n const channel = this._getOrCreateStream({\n tag,\n contentType: opts.contentType,\n });\n assert(!channel.push, `Channel already open: ${tag}`);\n\n // We need to buffer incoming data until the port is subscribed to.\n let inboundBuffer: Uint8Array[] = [];\n let callback: ((data: Uint8Array) => void) | undefined;\n\n channel.push = (data) => {\n channel.stats.bytesReceived += data.length;\n this._emitStats.schedule();\n if (callback) {\n callback(data);\n } else {\n inboundBuffer.push(data);\n }\n };\n\n const port: RpcPort = {\n send: (data: Uint8Array) => {\n this._sendData(channel, data); // TODO(dmaretskyi): Error propagation?\n\n // TODO(dmaretskyi): Debugging.\n // appendFileSync('log.json', JSON.stringify(schema.getCodecForType('dxos.rpc.RpcMessage').decode(data), null, 2) + '\\n')\n },\n subscribe: (cb: (data: Uint8Array) => void) => {\n assert(!callback, 'Only one subscriber is allowed');\n callback = cb;\n for (const data of inboundBuffer) {\n cb(data);\n }\n inboundBuffer = [];\n },\n };\n\n // NOTE: Make sure channel.push is set before sending the command.\n this._sendCommand({\n openChannel: {\n id: channel.id,\n tag: channel.tag,\n contentType: channel.contentType,\n },\n });\n\n return port;\n }\n\n /**\n * Force-close with optional error.\n */\n destroy(err?: Error) {\n if (this._destroying) {\n return;\n }\n this._destroying = true;\n\n this._sendCommand({\n destroy: {\n error: err?.message,\n },\n });\n this._dispose();\n }\n\n private _dispose(err?: Error) {\n if (this._destroyed) {\n return;\n }\n\n this._destroyed = true;\n this._framer.destroy();\n\n for (const channel of this._channelsByTag.values()) {\n channel.destroy?.(err);\n }\n\n this.close.emit(err);\n\n // Make it easy for GC.\n this._channelsByLocalId.clear();\n this._channelsByTag.clear();\n\n void this._ctx.dispose();\n }\n\n private _handleCommand(cmd: Command) {\n log('Received command', { cmd });\n\n if (this._destroyed || this._destroying) {\n log.warn('Received command after destroy');\n return;\n }\n\n if (cmd.openChannel) {\n const channel = this._getOrCreateStream({\n tag: cmd.openChannel.tag,\n contentType: cmd.openChannel.contentType,\n });\n channel.remoteId = cmd.openChannel.id;\n\n // Flush any buffered data.\n for (const data of channel.buffer) {\n this._sendCommand({\n data: {\n channelId: channel.remoteId,\n data,\n },\n });\n }\n channel.buffer = [];\n } else if (cmd.data) {\n const stream = this._channelsByLocalId.get(cmd.data.channelId) ?? failUndefined();\n if (!stream.push) {\n log.warn('Received data for channel before it was opened', { tag: stream.tag });\n return;\n }\n stream.push(cmd.data.data);\n } else if (cmd.destroy) {\n this._dispose();\n }\n }\n\n private _sendCommand(cmd: Command) {\n Promise.resolve(this._framer.port.send(codec.encode(cmd))).catch((err) => {\n this.destroy(err);\n });\n }\n\n private _getOrCreateStream(params: CreateChannelInternalParams): Channel {\n let channel = this._channelsByTag.get(params.tag);\n if (!channel) {\n channel = {\n id: this._nextId++,\n remoteId: null,\n tag: params.tag,\n contentType: params.contentType,\n buffer: [],\n push: null,\n destroy: null,\n stats: {\n bytesSent: 0,\n bytesReceived: 0,\n },\n };\n this._channelsByTag.set(channel.tag, channel);\n this._channelsByLocalId.set(channel.id, channel);\n }\n return channel;\n }\n\n private _sendData(channel: Channel, data: Uint8Array) {\n channel.stats.bytesSent += data.length;\n this._emitStats.schedule();\n if (channel.remoteId === null) {\n // Remote side has not opened the channel yet.\n channel.buffer.push(data);\n } else {\n this._sendCommand({\n data: {\n channelId: channel.remoteId,\n data,\n },\n });\n }\n }\n}\n\ntype Channel = {\n /**\n * Our local channel ID.\n * Incoming Data commands will have this ID.\n */\n id: number;\n tag: string;\n\n /**\n * Remote id is set when we receive an OpenChannel command.\n * The originating Data commands should carry this id.\n */\n remoteId: null | number;\n\n contentType?: string;\n\n /**\n * Send buffer.\n */\n buffer: Uint8Array[];\n\n /**\n * Set when we initialize a NodeJS stream or an RPC port consuming the channel.\n */\n push: null | ((data: Uint8Array) => void);\n\n destroy: null | ((err?: Error) => void);\n\n stats: {\n bytesSent: number;\n bytesReceived: number;\n };\n};\n\ntype CreateChannelInternalParams = {\n tag: string;\n contentType?: string;\n};\n", "//\n// Copyright 2022 DXOS.org\n//\n\nimport assert from 'node:assert';\nimport { Duplex } from 'node:stream';\n\nimport { asyncTimeout, scheduleTaskInterval, runInContextAsync, synchronized, scheduleTask, Event } from '@dxos/async';\nimport { Context } from '@dxos/context';\nimport { failUndefined } from '@dxos/debug';\nimport { PublicKey } from '@dxos/keys';\nimport { log } from '@dxos/log';\nimport { schema, RpcClosedError } from '@dxos/protocols';\nimport { ConnectionInfo } from '@dxos/protocols/proto/dxos/devtools/swarm';\nimport { ControlService } from '@dxos/protocols/proto/dxos/mesh/teleport/control';\nimport { createProtoRpcPeer, ProtoRpcPeer } from '@dxos/rpc';\nimport { Callback } from '@dxos/util';\n\nimport { CreateChannelOpts, Muxer, RpcPort } from './muxing';\n\nexport type TeleportParams = {\n initiator: boolean;\n localPeerId: PublicKey;\n remotePeerId: PublicKey;\n};\n\nexport class Teleport {\n public readonly initiator: boolean;\n public readonly localPeerId: PublicKey;\n public readonly remotePeerId: PublicKey;\n\n private readonly _ctx = new Context({\n onError: (err) => {\n void this.destroy(err).catch(() => {\n log.error('Error during destroy', err);\n });\n },\n });\n\n private readonly _muxer = new Muxer();\n\n private readonly _control = new ControlExtension({\n heartbeatInterval: 10_000,\n heartbeatTimeout: 10_000,\n onTimeout: () => {\n this.destroy(new Error('Connection timed out')).catch((err) => log.catch(err));\n },\n });\n\n private readonly _extensions = new Map<string, TeleportExtension>();\n private readonly _remoteExtensions = new Set<string>();\n\n private _open = false;\n\n constructor({ initiator, localPeerId, remotePeerId }: TeleportParams) {\n assert(typeof initiator === 'boolean');\n assert(PublicKey.isPublicKey(localPeerId));\n assert(PublicKey.isPublicKey(remotePeerId));\n assert(typeof initiator === 'boolean');\n this.initiator = initiator;\n this.localPeerId = localPeerId;\n this.remotePeerId = remotePeerId;\n\n this._control.onExtensionRegistered.set(async (name) => {\n log('remote extension', { name });\n assert(!this._remoteExtensions.has(name), 'Remote extension already exists');\n this._remoteExtensions.add(name);\n\n if (this._extensions.has(name)) {\n try {\n await this._openExtension(name);\n } catch (err: any) {\n await this.destroy(err);\n }\n }\n });\n\n {\n // Destroy Teleport when the stream is closed.\n this._muxer.stream.on('close', async () => {\n await this.destroy();\n });\n\n this._muxer.stream.on('error', async (err) => {\n await this.destroy(err);\n });\n }\n }\n\n get stream(): Duplex {\n return this._muxer.stream;\n }\n\n get stats(): Event<ConnectionInfo.StreamStats[]> {\n return this._muxer.statsUpdated;\n }\n\n /**\n * Blocks until the handshake is complete.\n */\n async open() {\n this._setExtension('dxos.mesh.teleport.control', this._control);\n await this._openExtension('dxos.mesh.teleport.control');\n this._open = true;\n }\n\n async close(err?: Error) {\n // TODO(dmaretskyi): Try soft close.\n\n await this.destroy(err);\n }\n\n @synchronized\n async destroy(err?: Error) {\n if (this._ctx.disposed) {\n return;\n }\n\n await this._ctx.dispose();\n\n for (const extension of this._extensions.values()) {\n try {\n await extension.onClose(err);\n } catch (err: any) {\n log.catch(err);\n }\n }\n\n this._muxer.destroy(err);\n }\n\n addExtension(name: string, extension: TeleportExtension) {\n if (!this._open) {\n throw new Error('Not open');\n }\n\n log('addExtension', { name });\n this._setExtension(name, extension);\n\n // Perform the registration in a separate tick as this might block while the remote side is opening the extension.\n scheduleTask(this._ctx, async () => {\n try {\n await this._control.registerExtension(name);\n } catch (err) {\n if (err instanceof RpcClosedError) {\n return;\n }\n throw err;\n }\n });\n\n if (this._remoteExtensions.has(name)) {\n // Open the extension in a separate tick.\n scheduleTask(this._ctx, async () => {\n await this._openExtension(name);\n });\n }\n }\n\n private _setExtension(extensionName: string, extension: TeleportExtension) {\n assert(!extensionName.includes('/'), 'Invalid extension name');\n assert(!this._extensions.has(extensionName), 'Extension already exists');\n this._extensions.set(extensionName, extension);\n }\n\n private async _openExtension(extensionName: string) {\n log('open extension', { extensionName });\n const extension = this._extensions.get(extensionName) ?? failUndefined();\n\n const context: ExtensionContext = {\n initiator: this.initiator,\n localPeerId: this.localPeerId,\n remotePeerId: this.remotePeerId,\n createPort: (channelName: string, opts?: CreateChannelOpts) => {\n assert(!channelName.includes('/'), 'Invalid channel name');\n return this._muxer.createPort(`${extensionName}/${channelName}`, opts);\n },\n createStream: (channelName: string, opts?: CreateChannelOpts) => {\n assert(!channelName.includes('/'), 'Invalid channel name');\n return this._muxer.createStream(`${extensionName}/${channelName}`, opts);\n },\n close: (err) => {\n void runInContextAsync(this._ctx, async () => {\n await this.close(err);\n });\n },\n };\n\n await extension.onOpen(context);\n log('extension opened', { extensionName });\n }\n}\n\nexport type ExtensionContext = {\n /**\n * One of the peers will be designated an initiator.\n */\n initiator: boolean;\n localPeerId: PublicKey;\n remotePeerId: PublicKey;\n createStream(tag: string, opts?: CreateChannelOpts): Duplex;\n createPort(tag: string, opts?: CreateChannelOpts): RpcPort;\n close(err?: Error): void;\n};\n\nexport interface TeleportExtension {\n onOpen(context: ExtensionContext): Promise<void>;\n onClose(err?: Error): Promise<void>;\n}\n\ntype ControlExtensionOpts = {\n heartbeatInterval: number;\n heartbeatTimeout: number;\n onTimeout: () => void;\n};\n\nclass ControlExtension implements TeleportExtension {\n private readonly _ctx = new Context({\n onError: (err) => {\n this._extensionContext.close(err);\n },\n });\n\n private _extensionContext!: ExtensionContext;\n private _rpc!: ProtoRpcPeer<{ Control: ControlService }>;\n\n public readonly onExtensionRegistered = new Callback<(extensionName: string) => void>();\n\n constructor(private readonly opts: ControlExtensionOpts) {}\n\n async onOpen(extensionContext: ExtensionContext): Promise<void> {\n this._extensionContext = extensionContext;\n\n // NOTE: Make sure that RPC timeout is greater than the heartbeat timeout.\n // TODO(dmaretskyi): Allow overwriting the timeout on individual RPC calls?\n this._rpc = createProtoRpcPeer<ControlRpcBundle, ControlRpcBundle>({\n requested: {\n Control: schema.getService('dxos.mesh.teleport.control.ControlService'),\n },\n exposed: {\n Control: schema.getService('dxos.mesh.teleport.control.ControlService'),\n },\n handlers: {\n Control: {\n registerExtension: async (request) => {\n this.onExtensionRegistered.call(request.name);\n },\n heartbeat: async (request) => {\n // Ok.\n },\n },\n },\n port: extensionContext.createPort('rpc', {\n contentType: 'application/x-protobuf; messagType=\"dxos.rpc.Message\"',\n }),\n });\n\n await this._rpc.open();\n\n scheduleTaskInterval(\n this._ctx,\n async () => {\n try {\n await asyncTimeout(this._rpc.rpc.Control.heartbeat(), this.opts.heartbeatTimeout);\n } catch (err: any) {\n this.opts.onTimeout();\n }\n },\n this.opts.heartbeatInterval,\n );\n }\n\n async onClose(err?: Error): Promise<void> {\n await this._ctx.dispose();\n await this._rpc.close();\n }\n\n async registerExtension(name: string) {\n await this._rpc.rpc.Control.registerExtension({ name });\n }\n}\n\ntype ControlRpcBundle = {\n Control: ControlService;\n};\n", "//\n// Copyright 2022 DXOS.org\n//\n\nimport assert from 'node:assert';\n\nimport { asyncTimeout, Trigger } from '@dxos/async';\nimport { log } from '@dxos/log';\nimport { schema } from '@dxos/protocols';\nimport { TestService } from '@dxos/protocols/proto/example/testing/rpc';\nimport { createProtoRpcPeer, ProtoRpcPeer } from '@dxos/rpc';\n\nimport { ExtensionContext, TeleportExtension } from '../teleport';\n\ninterface TestExtensionCallbacks {\n onOpen?: () => Promise<void>;\n onClose?: () => Promise<void>;\n}\n\nexport class TestExtension implements TeleportExtension {\n public readonly open = new Trigger();\n public readonly closed = new Trigger();\n public extensionContext: ExtensionContext | undefined;\n private _rpc!: ProtoRpcPeer<{ TestService: TestService }>;\n\n constructor(public readonly callbacks: TestExtensionCallbacks = {}) {}\n\n get remotePeerId() {\n return this.extensionContext?.remotePeerId;\n }\n\n async onOpen(context: ExtensionContext) {\n log('onOpen', { localPeerId: context.localPeerId, remotePeerId: context.remotePeerId });\n this.extensionContext = context;\n this._rpc = createProtoRpcPeer<{ TestService: TestService }, { TestService: TestService }>({\n port: context.createPort('rpc', {\n contentType: 'application/x-protobuf; messageType=\"dxos.rpc.Message\"',\n }),\n requested: {\n TestService: schema.getService('example.testing.rpc.TestService'),\n },\n exposed: {\n TestService: schema.getService('example.testing.rpc.TestService'),\n },\n handlers: {\n TestService: {\n voidCall: async (request) => {\n // Ok.\n },\n testCall: async (request) => {\n return {\n data: request.data,\n };\n },\n },\n },\n timeout: 1000,\n });\n\n await this._rpc.open();\n await this.callbacks.onOpen?.();\n\n this.open.wake();\n }\n\n async onClose(err?: Error) {\n log('onClose', { err });\n await this.callbacks.onClose?.();\n this.closed.wake();\n await this._rpc?.close();\n }\n\n async test(message = 'test') {\n await this.open.wait({ timeout: 500 });\n const res = await asyncTimeout(this._rpc.rpc.TestService.testCall({ data: message }), 500);\n assert(res.data === message);\n }\n\n /**\n * Force-close the connection.\n */\n async closeConnection(err?: Error) {\n this.extensionContext?.close(err);\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["assert", "Duplex", "varint", "Framer", "_stream", "objectMode", "read", "write", "chunk", "encoding", "callback", "_subscribeCb", "_buffer", "length", "Buffer", "concat", "_messageCb", "_popFrames", "undefined", "port", "send", "message", "push", "encodeFrame", "subscribe", "stream", "offset", "frame", "decodeFrame", "bytesConsumed", "payload", "subarray", "destroy", "buffer", "frameLength", "decode", "tagLength", "bytes", "err", "RangeError", "encodingLength", "allocUnsafe", "encode", "set", "assert", "Duplex", "DeferredTask", "Event", "sleep", "Context", "failUndefined", "log", "schema", "codec", "schema", "getCodecForType", "DEBOUNCE_STATS_INTERVAL", "Muxer", "constructor", "_framer", "Framer", "stream", "_channelsByLocalId", "Map", "_channelsByTag", "_nextId", "_destroyed", "_destroying", "close", "Event", "statsUpdated", "_ctx", "Context", "_emitStats", "DeferredTask", "emit", "Array", "from", "values", "map", "channel", "id", "tag", "bytesSent", "stats", "bytesReceived", "sleep", "port", "subscribe", "msg", "_handleCommand", "decode", "createStream", "opts", "_getOrCreateStream", "contentType", "assert", "push", "Duplex", "write", "data", "encoding", "callback", "_sendData", "read", "length", "schedule", "destroy", "err", "_sendCommand", "openChannel", "createPort", "inboundBuffer", "send", "cb", "error", "message", "_dispose", "clear", "dispose", "cmd", "log", "warn", "remoteId", "buffer", "channelId", "get", "failUndefined", "Promise", "resolve", "encode", "catch", "params", "set", "assert", "asyncTimeout", "scheduleTaskInterval", "runInContextAsync", "synchronized", "scheduleTask", "Context", "failUndefined", "PublicKey", "log", "schema", "RpcClosedError", "createProtoRpcPeer", "Callback", "Teleport", "constructor", "initiator", "localPeerId", "remotePeerId", "_ctx", "Context", "onError", "err", "destroy", "catch", "log", "error", "_muxer", "Muxer", "_control", "ControlExtension", "heartbeatInterval", "heartbeatTimeout", "onTimeout", "Error", "_extensions", "Map", "_remoteExtensions", "Set", "_open", "assert", "PublicKey", "isPublicKey", "onExtensionRegistered", "set", "name", "has", "add", "_openExtension", "stream", "on", "stats", "statsUpdated", "open", "_setExtension", "close", "disposed", "dispose", "extension", "values", "onClose", "addExtension", "scheduleTask", "registerExtension", "RpcClosedError", "extensionName", "includes", "get", "failUndefined", "context", "createPort", "channelName", "opts", "createStream", "runInContextAsync", "onOpen", "synchronized", "_extensionContext", "Callback", "extensionContext", "_rpc", "createProtoRpcPeer", "requested", "Control", "schema", "getService", "exposed", "handlers", "request", "call", "heartbeat", "port", "contentType", "scheduleTaskInterval", "asyncTimeout", "rpc", "assert", "asyncTimeout", "Trigger", "log", "schema", "createProtoRpcPeer", "TestExtension", "constructor", "callbacks", "open", "closed", "remotePeerId", "extensionContext", "onOpen", "context", "localPeerId", "_rpc", "port", "createPort", "contentType", "requested", "TestService", "getService", "exposed", "handlers", "voidCall", "request", "testCall", "data", "timeout", "wake", "onClose", "err", "close", "test", "message", "wait", "res", "rpc", "closeConnection"]
7
+ }
@@ -6,7 +6,7 @@ import {
6
6
  TestExtension,
7
7
  decodeFrame,
8
8
  encodeFrame
9
- } from "./chunk-NJQ5JWQJ.mjs";
9
+ } from "./chunk-XWWASTDK.mjs";
10
10
 
11
11
  // packages/core/mesh/teleport/src/rpc-extension.ts
12
12
  import assert from "@dxos/node-std/assert";
@@ -1 +1 @@
1
- {"inputs":{"packages/core/mesh/teleport/src/muxing/framer.ts":{"bytes":12789,"imports":[{"path":"@dxos/node-std/assert","kind":"import-statement","external":true},{"path":"@dxos/node-std/stream","kind":"import-statement","external":true},{"path":"varint","kind":"import-statement","external":true}]},"packages/core/mesh/teleport/src/muxing/muxer.ts":{"bytes":25294,"imports":[{"path":"@dxos/node-std/assert","kind":"import-statement","external":true},{"path":"@dxos/node-std/stream","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols","kind":"import-statement","external":true},{"path":"packages/core/mesh/teleport/src/muxing/framer.ts","kind":"import-statement","original":"./framer"}]},"packages/core/mesh/teleport/src/muxing/rpc-port.ts":{"bytes":824,"imports":[]},"packages/core/mesh/teleport/src/muxing/index.ts":{"bytes":539,"imports":[{"path":"packages/core/mesh/teleport/src/muxing/framer.ts","kind":"import-statement","original":"./framer"},{"path":"packages/core/mesh/teleport/src/muxing/muxer.ts","kind":"import-statement","original":"./muxer"},{"path":"packages/core/mesh/teleport/src/muxing/rpc-port.ts","kind":"import-statement","original":"./rpc-port"}]},"packages/core/mesh/teleport/src/teleport.ts":{"bytes":27956,"imports":[{"path":"@dxos/node-std/assert","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/keys","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols","kind":"import-statement","external":true},{"path":"@dxos/rpc","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"packages/core/mesh/teleport/src/muxing/index.ts","kind":"import-statement","original":"./muxing"}]},"packages/core/mesh/teleport/src/testing/test-extension.ts":{"bytes":8466,"imports":[{"path":"@dxos/node-std/assert","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols","kind":"import-statement","external":true},{"path":"@dxos/rpc","kind":"import-statement","external":true}]},"packages/core/mesh/teleport/src/rpc-extension.ts":{"bytes":5115,"imports":[{"path":"@dxos/node-std/assert","kind":"import-statement","external":true},{"path":"@dxos/rpc","kind":"import-statement","external":true}]},"packages/core/mesh/teleport/src/index.ts":{"bytes":685,"imports":[{"path":"packages/core/mesh/teleport/src/muxing/index.ts","kind":"import-statement","original":"./muxing"},{"path":"packages/core/mesh/teleport/src/teleport.ts","kind":"import-statement","original":"./teleport"},{"path":"packages/core/mesh/teleport/src/testing/test-extension.ts","kind":"import-statement","original":"./testing/test-extension"},{"path":"packages/core/mesh/teleport/src/rpc-extension.ts","kind":"import-statement","original":"./rpc-extension"}]},"packages/core/mesh/teleport/src/testing/test-builder.ts":{"bytes":13448,"imports":[{"path":"@dxos/node-std/assert","kind":"import-statement","external":true},{"path":"@dxos/node-std/stream","kind":"import-statement","external":true},{"path":"@dxos/keys","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"packages/core/mesh/teleport/src/teleport.ts","kind":"import-statement","original":"../teleport"}]},"packages/core/mesh/teleport/src/testing/index.ts":{"bytes":494,"imports":[{"path":"packages/core/mesh/teleport/src/testing/test-builder.ts","kind":"import-statement","original":"./test-builder"},{"path":"packages/core/mesh/teleport/src/testing/test-extension.ts","kind":"import-statement","original":"./test-extension"}]}},"outputs":{"packages/core/mesh/teleport/dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":2748},"packages/core/mesh/teleport/dist/lib/browser/index.mjs":{"imports":[{"path":"packages/core/mesh/teleport/dist/lib/browser/chunk-NJQ5JWQJ.mjs","kind":"import-statement"},{"path":"@dxos/node-std/assert","kind":"import-statement","external":true},{"path":"@dxos/rpc","kind":"import-statement","external":true}],"exports":["Framer","Muxer","RpcExtension","Teleport","TestExtension","decodeFrame","encodeFrame"],"entryPoint":"packages/core/mesh/teleport/src/index.ts","inputs":{"packages/core/mesh/teleport/src/index.ts":{"bytesInOutput":0},"packages/core/mesh/teleport/src/rpc-extension.ts":{"bytesInOutput":1094}},"bytes":1436},"packages/core/mesh/teleport/dist/lib/browser/testing/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":7000},"packages/core/mesh/teleport/dist/lib/browser/testing/index.mjs":{"imports":[{"path":"packages/core/mesh/teleport/dist/lib/browser/chunk-NJQ5JWQJ.mjs","kind":"import-statement"},{"path":"@dxos/node-std/assert","kind":"import-statement","external":true},{"path":"@dxos/node-std/stream","kind":"import-statement","external":true},{"path":"@dxos/keys","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true}],"exports":["TestBuilder","TestConnection","TestExtension","TestPeer"],"entryPoint":"packages/core/mesh/teleport/src/testing/index.ts","inputs":{"packages/core/mesh/teleport/src/testing/test-builder.ts":{"bytesInOutput":3472},"packages/core/mesh/teleport/src/testing/index.ts":{"bytesInOutput":0}},"bytes":3741},"packages/core/mesh/teleport/dist/lib/browser/chunk-NJQ5JWQJ.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":36730},"packages/core/mesh/teleport/dist/lib/browser/chunk-NJQ5JWQJ.mjs":{"imports":[{"path":"@dxos/node-std/assert","kind":"import-statement","external":true},{"path":"@dxos/node-std/stream","kind":"import-statement","external":true},{"path":"varint","kind":"import-statement","external":true},{"path":"@dxos/node-std/assert","kind":"import-statement","external":true},{"path":"@dxos/node-std/stream","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols","kind":"import-statement","external":true},{"path":"@dxos/node-std/assert","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/keys","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols","kind":"import-statement","external":true},{"path":"@dxos/rpc","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"@dxos/node-std/assert","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols","kind":"import-statement","external":true},{"path":"@dxos/rpc","kind":"import-statement","external":true}],"exports":["Framer","Muxer","Teleport","TestExtension","decodeFrame","encodeFrame"],"inputs":{"packages/core/mesh/teleport/src/muxing/framer.ts":{"bytesInOutput":2645},"packages/core/mesh/teleport/src/muxing/muxer.ts":{"bytesInOutput":5694},"packages/core/mesh/teleport/src/muxing/index.ts":{"bytesInOutput":0},"packages/core/mesh/teleport/src/teleport.ts":{"bytesInOutput":7413},"packages/core/mesh/teleport/src/testing/test-extension.ts":{"bytesInOutput":2378}},"bytes":18511}}}
1
+ {"inputs":{"packages/core/mesh/teleport/src/muxing/framer.ts":{"bytes":12789,"imports":[{"path":"@dxos/node-std/assert","kind":"import-statement","external":true},{"path":"@dxos/node-std/stream","kind":"import-statement","external":true},{"path":"varint","kind":"import-statement","external":true}]},"packages/core/mesh/teleport/src/muxing/muxer.ts":{"bytes":29354,"imports":[{"path":"@dxos/node-std/assert","kind":"import-statement","external":true},{"path":"@dxos/node-std/stream","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols","kind":"import-statement","external":true},{"path":"packages/core/mesh/teleport/src/muxing/framer.ts","kind":"import-statement","original":"./framer"}]},"packages/core/mesh/teleport/src/muxing/rpc-port.ts":{"bytes":824,"imports":[]},"packages/core/mesh/teleport/src/muxing/index.ts":{"bytes":539,"imports":[{"path":"packages/core/mesh/teleport/src/muxing/framer.ts","kind":"import-statement","original":"./framer"},{"path":"packages/core/mesh/teleport/src/muxing/muxer.ts","kind":"import-statement","original":"./muxer"},{"path":"packages/core/mesh/teleport/src/muxing/rpc-port.ts","kind":"import-statement","original":"./rpc-port"}]},"packages/core/mesh/teleport/src/teleport.ts":{"bytes":28385,"imports":[{"path":"@dxos/node-std/assert","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/keys","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols","kind":"import-statement","external":true},{"path":"@dxos/rpc","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"packages/core/mesh/teleport/src/muxing/index.ts","kind":"import-statement","original":"./muxing"}]},"packages/core/mesh/teleport/src/testing/test-extension.ts":{"bytes":8466,"imports":[{"path":"@dxos/node-std/assert","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols","kind":"import-statement","external":true},{"path":"@dxos/rpc","kind":"import-statement","external":true}]},"packages/core/mesh/teleport/src/rpc-extension.ts":{"bytes":5115,"imports":[{"path":"@dxos/node-std/assert","kind":"import-statement","external":true},{"path":"@dxos/rpc","kind":"import-statement","external":true}]},"packages/core/mesh/teleport/src/index.ts":{"bytes":685,"imports":[{"path":"packages/core/mesh/teleport/src/muxing/index.ts","kind":"import-statement","original":"./muxing"},{"path":"packages/core/mesh/teleport/src/teleport.ts","kind":"import-statement","original":"./teleport"},{"path":"packages/core/mesh/teleport/src/testing/test-extension.ts","kind":"import-statement","original":"./testing/test-extension"},{"path":"packages/core/mesh/teleport/src/rpc-extension.ts","kind":"import-statement","original":"./rpc-extension"}]},"packages/core/mesh/teleport/src/testing/test-builder.ts":{"bytes":13448,"imports":[{"path":"@dxos/node-std/assert","kind":"import-statement","external":true},{"path":"@dxos/node-std/stream","kind":"import-statement","external":true},{"path":"@dxos/keys","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"packages/core/mesh/teleport/src/teleport.ts","kind":"import-statement","original":"../teleport"}]},"packages/core/mesh/teleport/src/testing/index.ts":{"bytes":494,"imports":[{"path":"packages/core/mesh/teleport/src/testing/test-builder.ts","kind":"import-statement","original":"./test-builder"},{"path":"packages/core/mesh/teleport/src/testing/test-extension.ts","kind":"import-statement","original":"./test-extension"}]}},"outputs":{"packages/core/mesh/teleport/dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":2748},"packages/core/mesh/teleport/dist/lib/browser/index.mjs":{"imports":[{"path":"packages/core/mesh/teleport/dist/lib/browser/chunk-XWWASTDK.mjs","kind":"import-statement"},{"path":"@dxos/node-std/assert","kind":"import-statement","external":true},{"path":"@dxos/rpc","kind":"import-statement","external":true}],"exports":["Framer","Muxer","RpcExtension","Teleport","TestExtension","decodeFrame","encodeFrame"],"entryPoint":"packages/core/mesh/teleport/src/index.ts","inputs":{"packages/core/mesh/teleport/src/index.ts":{"bytesInOutput":0},"packages/core/mesh/teleport/src/rpc-extension.ts":{"bytesInOutput":1094}},"bytes":1436},"packages/core/mesh/teleport/dist/lib/browser/testing/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":7000},"packages/core/mesh/teleport/dist/lib/browser/testing/index.mjs":{"imports":[{"path":"packages/core/mesh/teleport/dist/lib/browser/chunk-XWWASTDK.mjs","kind":"import-statement"},{"path":"@dxos/node-std/assert","kind":"import-statement","external":true},{"path":"@dxos/node-std/stream","kind":"import-statement","external":true},{"path":"@dxos/keys","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true}],"exports":["TestBuilder","TestConnection","TestExtension","TestPeer"],"entryPoint":"packages/core/mesh/teleport/src/testing/index.ts","inputs":{"packages/core/mesh/teleport/src/testing/test-builder.ts":{"bytesInOutput":3472},"packages/core/mesh/teleport/src/testing/index.ts":{"bytesInOutput":0}},"bytes":3741},"packages/core/mesh/teleport/dist/lib/browser/chunk-XWWASTDK.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":39096},"packages/core/mesh/teleport/dist/lib/browser/chunk-XWWASTDK.mjs":{"imports":[{"path":"@dxos/node-std/assert","kind":"import-statement","external":true},{"path":"@dxos/node-std/stream","kind":"import-statement","external":true},{"path":"varint","kind":"import-statement","external":true},{"path":"@dxos/node-std/assert","kind":"import-statement","external":true},{"path":"@dxos/node-std/stream","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols","kind":"import-statement","external":true},{"path":"@dxos/node-std/assert","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/keys","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols","kind":"import-statement","external":true},{"path":"@dxos/rpc","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"@dxos/node-std/assert","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols","kind":"import-statement","external":true},{"path":"@dxos/rpc","kind":"import-statement","external":true}],"exports":["Framer","Muxer","Teleport","TestExtension","decodeFrame","encodeFrame"],"inputs":{"packages/core/mesh/teleport/src/muxing/framer.ts":{"bytesInOutput":2645},"packages/core/mesh/teleport/src/muxing/muxer.ts":{"bytesInOutput":6648},"packages/core/mesh/teleport/src/muxing/index.ts":{"bytesInOutput":0},"packages/core/mesh/teleport/src/teleport.ts":{"bytesInOutput":7484},"packages/core/mesh/teleport/src/testing/test-extension.ts":{"bytesInOutput":2378}},"bytes":19536}}}
@@ -2,7 +2,7 @@ import "@dxos/node-std/globals"
2
2
  import {
3
3
  Teleport,
4
4
  TestExtension
5
- } from "../chunk-NJQ5JWQJ.mjs";
5
+ } from "../chunk-XWWASTDK.mjs";
6
6
 
7
7
  // packages/core/mesh/teleport/src/testing/test-builder.ts
8
8
  import assert from "@dxos/node-std/assert";
@@ -145,10 +145,12 @@ var encodeFrame = (payload) => {
145
145
  var import_node_assert2 = __toESM(require("node:assert"));
146
146
  var import_node_stream2 = require("node:stream");
147
147
  var import_async = require("@dxos/async");
148
+ var import_context = require("@dxos/context");
148
149
  var import_debug = require("@dxos/debug");
149
150
  var import_log = require("@dxos/log");
150
151
  var import_protocols = require("@dxos/protocols");
151
152
  var codec = import_protocols.schema.getCodecForType("dxos.mesh.muxer.Command");
153
+ var DEBOUNCE_STATS_INTERVAL = 1e3;
152
154
  var Muxer = class {
153
155
  constructor() {
154
156
  this._framer = new Framer();
@@ -159,6 +161,20 @@ var Muxer = class {
159
161
  this._destroyed = false;
160
162
  this._destroying = false;
161
163
  this.close = new import_async.Event();
164
+ this.statsUpdated = new import_async.Event();
165
+ this._ctx = new import_context.Context();
166
+ this._emitStats = new import_async.DeferredTask(this._ctx, async () => {
167
+ if (this._destroyed || this._destroying) {
168
+ return;
169
+ }
170
+ this.statsUpdated.emit(Array.from(this._channelsByTag.values()).map((channel) => ({
171
+ id: channel.id,
172
+ tag: channel.tag,
173
+ bytesSent: channel.stats.bytesSent,
174
+ bytesReceived: channel.stats.bytesReceived
175
+ })));
176
+ await (0, import_async.sleep)(DEBOUNCE_STATS_INTERVAL);
177
+ });
162
178
  this._framer.port.subscribe((msg) => {
163
179
  this._handleCommand(codec.decode(msg));
164
180
  });
@@ -184,6 +200,8 @@ var Muxer = class {
184
200
  }
185
201
  });
186
202
  channel.push = (data) => {
203
+ channel.stats.bytesReceived += data.length;
204
+ this._emitStats.schedule();
187
205
  stream.push(data);
188
206
  };
189
207
  channel.destroy = (err) => {
@@ -213,6 +231,8 @@ var Muxer = class {
213
231
  let inboundBuffer = [];
214
232
  let callback;
215
233
  channel.push = (data) => {
234
+ channel.stats.bytesReceived += data.length;
235
+ this._emitStats.schedule();
216
236
  if (callback) {
217
237
  callback(data);
218
238
  } else {
@@ -269,6 +289,7 @@ var Muxer = class {
269
289
  this.close.emit(err);
270
290
  this._channelsByLocalId.clear();
271
291
  this._channelsByTag.clear();
292
+ void this._ctx.dispose();
272
293
  }
273
294
  _handleCommand(cmd) {
274
295
  var _a;
@@ -276,14 +297,14 @@ var Muxer = class {
276
297
  cmd
277
298
  }, {
278
299
  file: "muxer.ts",
279
- line: 194,
300
+ line: 224,
280
301
  scope: this,
281
302
  callSite: (f, a) => f(...a)
282
303
  });
283
304
  if (this._destroyed || this._destroying) {
284
305
  import_log.log.warn("Received command after destroy", {}, {
285
306
  file: "muxer.ts",
286
- line: 197,
307
+ line: 227,
287
308
  scope: this,
288
309
  callSite: (f, a) => f(...a)
289
310
  });
@@ -311,7 +332,7 @@ var Muxer = class {
311
332
  tag: stream.tag
312
333
  }, {
313
334
  file: "muxer.ts",
314
- line: 221,
335
+ line: 251,
315
336
  scope: this,
316
337
  callSite: (f, a) => f(...a)
317
338
  });
@@ -337,7 +358,11 @@ var Muxer = class {
337
358
  contentType: params.contentType,
338
359
  buffer: [],
339
360
  push: null,
340
- destroy: null
361
+ destroy: null,
362
+ stats: {
363
+ bytesSent: 0,
364
+ bytesReceived: 0
365
+ }
341
366
  };
342
367
  this._channelsByTag.set(channel.tag, channel);
343
368
  this._channelsByLocalId.set(channel.id, channel);
@@ -345,6 +370,8 @@ var Muxer = class {
345
370
  return channel;
346
371
  }
347
372
  _sendData(channel, data) {
373
+ channel.stats.bytesSent += data.length;
374
+ this._emitStats.schedule();
348
375
  if (channel.remoteId === null) {
349
376
  channel.buffer.push(data);
350
377
  } else {
@@ -361,7 +388,7 @@ var Muxer = class {
361
388
  // packages/core/mesh/teleport/src/teleport.ts
362
389
  var import_node_assert3 = __toESM(require("node:assert"));
363
390
  var import_async2 = require("@dxos/async");
364
- var import_context = require("@dxos/context");
391
+ var import_context2 = require("@dxos/context");
365
392
  var import_debug2 = require("@dxos/debug");
366
393
  var import_keys = require("@dxos/keys");
367
394
  var import_log2 = require("@dxos/log");
@@ -380,12 +407,12 @@ var __decorate = function(decorators, target, key, desc) {
380
407
  };
381
408
  var Teleport = class {
382
409
  constructor({ initiator, localPeerId, remotePeerId }) {
383
- this._ctx = new import_context.Context({
410
+ this._ctx = new import_context2.Context({
384
411
  onError: (err) => {
385
412
  void this.destroy(err).catch(() => {
386
413
  import_log2.log.error("Error during destroy", err, {
387
414
  file: "teleport.ts",
388
- line: 34,
415
+ line: 35,
389
416
  scope: this,
390
417
  callSite: (f, a) => f(...a)
391
418
  });
@@ -399,7 +426,7 @@ var Teleport = class {
399
426
  onTimeout: () => {
400
427
  this.destroy(new Error("Connection timed out")).catch((err) => import_log2.log.catch(err, {}, {
401
428
  file: "teleport.ts",
402
- line: 45,
429
+ line: 46,
403
430
  scope: this,
404
431
  callSite: (f, a) => f(...a)
405
432
  }));
@@ -420,7 +447,7 @@ var Teleport = class {
420
447
  name
421
448
  }, {
422
449
  file: "teleport.ts",
423
- line: 64,
450
+ line: 65,
424
451
  scope: this,
425
452
  callSite: (f, a) => f(...a)
426
453
  });
@@ -446,6 +473,9 @@ var Teleport = class {
446
473
  get stream() {
447
474
  return this._muxer.stream;
448
475
  }
476
+ get stats() {
477
+ return this._muxer.statsUpdated;
478
+ }
449
479
  /**
450
480
  * Blocks until the handshake is complete.
451
481
  */
@@ -468,7 +498,7 @@ var Teleport = class {
468
498
  } catch (err1) {
469
499
  import_log2.log.catch(err1, {}, {
470
500
  file: "teleport.ts",
471
- line: 120,
501
+ line: 125,
472
502
  scope: this,
473
503
  callSite: (f, a) => f(...a)
474
504
  });
@@ -484,7 +514,7 @@ var Teleport = class {
484
514
  name
485
515
  }, {
486
516
  file: "teleport.ts",
487
- line: 132,
517
+ line: 137,
488
518
  scope: this,
489
519
  callSite: (f, a) => f(...a)
490
520
  });
@@ -516,7 +546,7 @@ var Teleport = class {
516
546
  extensionName
517
547
  }, {
518
548
  file: "teleport.ts",
519
- line: 162,
549
+ line: 167,
520
550
  scope: this,
521
551
  callSite: (f, a) => f(...a)
522
552
  });
@@ -544,7 +574,7 @@ var Teleport = class {
544
574
  extensionName
545
575
  }, {
546
576
  file: "teleport.ts",
547
- line: 185,
577
+ line: 190,
548
578
  scope: this,
549
579
  callSite: (f, a) => f(...a)
550
580
  });
@@ -556,7 +586,7 @@ __decorate([
556
586
  var ControlExtension = class {
557
587
  constructor(opts) {
558
588
  this.opts = opts;
559
- this._ctx = new import_context.Context({
589
+ this._ctx = new import_context2.Context({
560
590
  onError: (err) => {
561
591
  this._extensionContext.close(err);
562
592
  }