@dxos/network-manager 0.3.9-main.b7e6a67 → 0.3.9-main.c7cd0ec

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 (87) hide show
  1. package/dist/lib/browser/{chunk-LA2ACGLR.mjs → chunk-XF474R3E.mjs} +434 -116
  2. package/dist/lib/browser/chunk-XF474R3E.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +1 -11
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/browser/testing/index.mjs +3 -3
  6. package/dist/lib/node/{chunk-QWUG7JSH.cjs → chunk-Y2B5BDRH.cjs} +426 -104
  7. package/dist/lib/node/chunk-Y2B5BDRH.cjs.map +7 -0
  8. package/dist/lib/node/index.cjs +27 -36
  9. package/dist/lib/node/index.cjs.map +2 -2
  10. package/dist/lib/node/meta.json +1 -1
  11. package/dist/lib/node/testing/index.cjs +18 -19
  12. package/dist/lib/node/testing/index.cjs.map +1 -1
  13. package/dist/types/src/connection-log.d.ts.map +1 -1
  14. package/dist/types/src/swarm/connection.d.ts +4 -1
  15. package/dist/types/src/swarm/connection.d.ts.map +1 -1
  16. package/dist/types/src/topology/mmst-topology.d.ts +1 -0
  17. package/dist/types/src/topology/mmst-topology.d.ts.map +1 -1
  18. package/dist/types/src/transport/index.d.ts +0 -1
  19. package/dist/types/src/transport/index.d.ts.map +1 -1
  20. package/dist/types/src/transport/libdatachannel-transport.d.ts +4 -1
  21. package/dist/types/src/transport/libdatachannel-transport.d.ts.map +1 -1
  22. package/dist/types/src/transport/memory-transport.d.ts +3 -1
  23. package/dist/types/src/transport/memory-transport.d.ts.map +1 -1
  24. package/dist/types/src/transport/simplepeer-transport-proxy.d.ts +3 -1
  25. package/dist/types/src/transport/simplepeer-transport-proxy.d.ts.map +1 -1
  26. package/dist/types/src/transport/simplepeer-transport-service.d.ts +3 -1
  27. package/dist/types/src/transport/simplepeer-transport-service.d.ts.map +1 -1
  28. package/dist/types/src/transport/simplepeer-transport.d.ts +7 -1
  29. package/dist/types/src/transport/simplepeer-transport.d.ts.map +1 -1
  30. package/dist/types/src/transport/tcp-transport.browser.d.ts +3 -1
  31. package/dist/types/src/transport/tcp-transport.browser.d.ts.map +1 -1
  32. package/dist/types/src/transport/tcp-transport.d.ts +3 -1
  33. package/dist/types/src/transport/tcp-transport.d.ts.map +1 -1
  34. package/dist/types/src/transport/transport.d.ts +17 -0
  35. package/dist/types/src/transport/transport.d.ts.map +1 -1
  36. package/dist/types/src/wire-protocol.d.ts +1 -1
  37. package/dist/types/src/wire-protocol.d.ts.map +1 -1
  38. package/package.json +18 -18
  39. package/src/connection-log.ts +14 -1
  40. package/src/swarm/connection.ts +40 -6
  41. package/src/topology/mmst-topology.ts +34 -6
  42. package/src/transport/index.ts +0 -1
  43. package/src/transport/libdatachannel-transport.test.ts +0 -4
  44. package/src/transport/libdatachannel-transport.ts +90 -8
  45. package/src/transport/memory-transport.ts +14 -1
  46. package/src/transport/simplepeer-transport-proxy.ts +9 -1
  47. package/src/transport/simplepeer-transport-service.ts +14 -0
  48. package/src/transport/simplepeer-transport.ts +70 -4
  49. package/src/transport/tcp-transport.browser.ts +9 -1
  50. package/src/transport/tcp-transport.ts +19 -1
  51. package/src/transport/transport.ts +19 -0
  52. package/src/wire-protocol.ts +3 -3
  53. package/dist/lib/browser/chunk-LA2ACGLR.mjs.map +0 -7
  54. package/dist/lib/browser/chunk-YERMWDRB.mjs +0 -24
  55. package/dist/lib/browser/chunk-YERMWDRB.mjs.map +0 -7
  56. package/dist/lib/browser/index.browser-O53CPVK3.mjs +0 -14
  57. package/dist/lib/browser/index.browser-O53CPVK3.mjs.map +0 -7
  58. package/dist/lib/node/chunk-QWUG7JSH.cjs.map +0 -7
  59. package/dist/lib/node/chunk-XE5JOIGD.cjs +0 -462
  60. package/dist/lib/node/chunk-XE5JOIGD.cjs.map +0 -7
  61. package/dist/lib/node/datachannel-53JZPGFA.cjs +0 -35
  62. package/dist/lib/node/datachannel-53JZPGFA.cjs.map +0 -7
  63. package/dist/types/src/transport/datachannel/index.browser.d.ts +0 -15
  64. package/dist/types/src/transport/datachannel/index.browser.d.ts.map +0 -1
  65. package/dist/types/src/transport/datachannel/index.d.ts +0 -8
  66. package/dist/types/src/transport/datachannel/index.d.ts.map +0 -1
  67. package/dist/types/src/transport/datachannel/rtc-data-channel.d.ts +0 -29
  68. package/dist/types/src/transport/datachannel/rtc-data-channel.d.ts.map +0 -1
  69. package/dist/types/src/transport/datachannel/rtc-events.d.ts +0 -9
  70. package/dist/types/src/transport/datachannel/rtc-events.d.ts.map +0 -1
  71. package/dist/types/src/transport/datachannel/rtc-ice-candidate.d.ts +0 -22
  72. package/dist/types/src/transport/datachannel/rtc-ice-candidate.d.ts.map +0 -1
  73. package/dist/types/src/transport/datachannel/rtc-peer-connection.d.ts +0 -47
  74. package/dist/types/src/transport/datachannel/rtc-peer-connection.d.ts.map +0 -1
  75. package/dist/types/src/transport/datachannel/rtc-peer-connection.test.d.ts +0 -2
  76. package/dist/types/src/transport/datachannel/rtc-peer-connection.test.d.ts.map +0 -1
  77. package/dist/types/src/transport/datachannel/rtc-session-description.d.ts +0 -10
  78. package/dist/types/src/transport/datachannel/rtc-session-description.d.ts.map +0 -1
  79. package/src/transport/datachannel/README.md +0 -2
  80. package/src/transport/datachannel/index.browser.ts +0 -8
  81. package/src/transport/datachannel/index.ts +0 -17
  82. package/src/transport/datachannel/rtc-data-channel.ts +0 -148
  83. package/src/transport/datachannel/rtc-events.ts +0 -23
  84. package/src/transport/datachannel/rtc-ice-candidate.ts +0 -54
  85. package/src/transport/datachannel/rtc-peer-connection.test.ts +0 -112
  86. package/src/transport/datachannel/rtc-peer-connection.ts +0 -347
  87. package/src/transport/datachannel/rtc-session-description.ts +0 -23
@@ -1 +1 @@
1
- {"version":3,"file":"simplepeer-transport-service.d.ts","sourceRoot":"","sources":["../../../../src/transport/simplepeer-transport-service.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAI9C,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,WAAW,EAEhB,KAAK,YAAY,EAClB,MAAM,wCAAwC,CAAC;AAYhD,qBAAa,0BAA2B,YAAW,aAAa;IAGlD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC;IAF3C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA6D;gBAE3D,aAAa,CAAC,KAAK;IAEhD,IAAI,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAAC,WAAW,CAAC;IA2E/C,UAAU,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAK7D,QAAQ,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAc1D,KAAK,CAAC,EAAE,OAAO,EAAE,EAAE,YAAY;CAQtC"}
1
+ {"version":3,"file":"simplepeer-transport-service.d.ts","sourceRoot":"","sources":["../../../../src/transport/simplepeer-transport-service.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAI9C,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,WAAW,EAEhB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,aAAa,EACnB,MAAM,wCAAwC,CAAC;AAYhD,qBAAa,0BAA2B,YAAW,aAAa;IAGlD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC;IAF3C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA6D;gBAE3D,aAAa,CAAC,KAAK;IAEhD,IAAI,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAAC,WAAW,CAAC;IA2E/C,UAAU,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAK7D,UAAU,CAAC,EAAE,OAAO,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAKjE,QAAQ,CAAC,EAAE,OAAO,EAAE,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IAK3D,QAAQ,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAc1D,KAAK,CAAC,EAAE,OAAO,EAAE,EAAE,YAAY;CAQtC"}
@@ -2,7 +2,7 @@
2
2
  import { Event } from '@dxos/async';
3
3
  import { ErrorStream } from '@dxos/debug';
4
4
  import { type Signal } from '@dxos/protocols/proto/dxos/mesh/swarm';
5
- import { type Transport, type TransportFactory } from './transport';
5
+ import { type Transport, type TransportFactory, type TransportStats } from './transport';
6
6
  export type SimplePeerTransportParams = {
7
7
  initiator: boolean;
8
8
  stream: NodeJS.ReadWriteStream;
@@ -21,7 +21,13 @@ export declare class SimplePeerTransport implements Transport {
21
21
  readonly connected: Event<void>;
22
22
  readonly errors: ErrorStream;
23
23
  private readonly _instanceId;
24
+ /**
25
+ * @params opts.config formatted as per https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/RTCPeerConnection
26
+ */
24
27
  constructor(params: SimplePeerTransportParams);
28
+ getStats(): Promise<TransportStats>;
29
+ _getStats(): Promise<any>;
30
+ getDetails(): Promise<string>;
25
31
  destroy(): Promise<void>;
26
32
  signal(signal: Signal): void;
27
33
  private _disconnectStreams;
@@ -1 +1 @@
1
- {"version":3,"file":"simplepeer-transport.d.ts","sourceRoot":"","sources":["../../../../src/transport/simplepeer-transport.ts"],"names":[],"mappings":";AAQA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,WAAW,EAAS,MAAM,aAAa,CAAC;AAIjD,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,uCAAuC,CAAC;AAEpE,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAGpE,MAAM,MAAM,yBAAyB,GAAG;IACtC,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC,eAAe,CAAC;IAC/B,YAAY,CAAC,EAAE,GAAG,CAAC;IACnB,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/C,CAAC;AAEF;;GAEG;AACH,qBAAa,mBAAoB,YAAW,SAAS;IAWvC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAVnC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAa;IACnC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAS;IAEvB,QAAQ,CAAC,MAAM,cAAe;IAC9B,QAAQ,CAAC,SAAS,cAAe;IACjC,QAAQ,CAAC,MAAM,cAAqB;IAEpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA8B;gBAE7B,MAAM,EAAE,yBAAyB;IAqFxD,OAAO;IAYb,MAAM,CAAC,MAAM,EAAE,MAAM;IASrB,OAAO,CAAC,kBAAkB;CAM3B;AAED,eAAO,MAAM,gCAAgC,kBAAmB,GAAG,KAAG,gBAMpE,CAAC"}
1
+ {"version":3,"file":"simplepeer-transport.d.ts","sourceRoot":"","sources":["../../../../src/transport/simplepeer-transport.ts"],"names":[],"mappings":";AAQA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,WAAW,EAAS,MAAM,aAAa,CAAC;AAIjD,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,uCAAuC,CAAC;AAEpE,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,gBAAgB,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAGzF,MAAM,MAAM,yBAAyB,GAAG;IACtC,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC,eAAe,CAAC;IAC/B,YAAY,CAAC,EAAE,GAAG,CAAC;IACnB,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/C,CAAC;AAEF;;GAEG;AACH,qBAAa,mBAAoB,YAAW,SAAS;IAcvC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAbnC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAa;IACnC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAS;IAEvB,QAAQ,CAAC,MAAM,cAAe;IAC9B,QAAQ,CAAC,SAAS,cAAe;IACjC,QAAQ,CAAC,MAAM,cAAqB;IAEpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA8B;IAE1D;;OAEG;gBAC0B,MAAM,EAAE,yBAAyB;IAyFxD,QAAQ,IAAI,OAAO,CAAC,cAAc,CAAC;IAsBnC,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC;IAwBzB,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAa7B,OAAO;IAYb,MAAM,CAAC,MAAM,EAAE,MAAM;IASrB,OAAO,CAAC,kBAAkB;CAM3B;AAED,eAAO,MAAM,gCAAgC,kBAAmB,GAAG,KAAG,gBAMpE,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { Event } from '@dxos/async';
2
2
  import { ErrorStream } from '@dxos/debug';
3
- import { type Transport, type TransportFactory } from './transport';
3
+ import { type Transport, type TransportFactory, type TransportStats } from './transport';
4
4
  export declare const TcpTransportFactory: TransportFactory;
5
5
  export declare class TcpTransport implements Transport {
6
6
  readonly closed: Event<void>;
@@ -8,5 +8,7 @@ export declare class TcpTransport implements Transport {
8
8
  readonly errors: ErrorStream;
9
9
  destroy(): Promise<void>;
10
10
  signal(): void;
11
+ getStats(): Promise<TransportStats>;
12
+ getDetails(): Promise<string>;
11
13
  }
12
14
  //# sourceMappingURL=tcp-transport.browser.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tcp-transport.browser.d.ts","sourceRoot":"","sources":["../../../../src/transport/tcp-transport.browser.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAIpE,eAAO,MAAM,mBAAmB,EAAE,gBAEjC,CAAC;AAEF,qBAAa,YAAa,YAAW,SAAS;IAC5C,SAAgB,MAAM,cAAqB;IAC3C,SAAgB,SAAS,cAAqB;IAC9C,SAAgB,MAAM,cAAqB;IAErC,OAAO;IAIb,MAAM;CAGP"}
1
+ {"version":3,"file":"tcp-transport.browser.d.ts","sourceRoot":"","sources":["../../../../src/transport/tcp-transport.browser.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,gBAAgB,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAIzF,eAAO,MAAM,mBAAmB,EAAE,gBAEjC,CAAC;AAEF,qBAAa,YAAa,YAAW,SAAS;IAC5C,SAAgB,MAAM,cAAqB;IAC3C,SAAgB,SAAS,cAAqB;IAC9C,SAAgB,MAAM,cAAqB;IAErC,OAAO;IAIb,MAAM;IAIA,QAAQ,IAAI,OAAO,CAAC,cAAc,CAAC;IAInC,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;CAGpC"}
@@ -1,7 +1,7 @@
1
1
  import { Event } from '@dxos/async';
2
2
  import { ErrorStream } from '@dxos/debug';
3
3
  import { type Signal } from '@dxos/protocols/proto/dxos/mesh/swarm';
4
- import { type Transport, type TransportFactory, type TransportOptions } from './transport';
4
+ import { type Transport, type TransportFactory, type TransportOptions, type TransportStats } from './transport';
5
5
  export declare const TcpTransportFactory: TransportFactory;
6
6
  /**
7
7
  * Fake transport.
@@ -18,6 +18,8 @@ export declare class TcpTransport implements Transport {
18
18
  constructor(options: TransportOptions);
19
19
  destroy(): Promise<void>;
20
20
  signal({ payload }: Signal): void;
21
+ getDetails(): Promise<string>;
22
+ getStats(): Promise<TransportStats>;
21
23
  private _handleSocket;
22
24
  }
23
25
  //# sourceMappingURL=tcp-transport.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tcp-transport.d.ts","sourceRoot":"","sources":["../../../../src/transport/tcp-transport.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,uCAAuC,CAAC;AAEpE,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE3F,eAAO,MAAM,mBAAmB,EAAE,gBAEjC,CAAC;AAEF;;GAEG;AACH,qBAAa,YAAa,YAAW,SAAS;IAYhC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAXpC,OAAO,CAAC,OAAO,CAAC,CAAqB;IACrC,OAAO,CAAC,OAAO,CAAC,CAAqB;IAErC,SAAgB,MAAM,cAAqB;IAC3C,SAAgB,SAAS,cAAqB;IAC9C,SAAgB,MAAM,cAAqB;IAE3C,OAAO,CAAC,UAAU,CAAS;IAE3B,OAAO,CAAC,UAAU,CAAS;gBAEE,OAAO,EAAE,gBAAgB;IAsChD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ9B,MAAM,CAAC,EAAE,OAAO,EAAE,EAAE,MAAM;IAW1B,OAAO,CAAC,aAAa;CAiBtB"}
1
+ {"version":3,"file":"tcp-transport.d.ts","sourceRoot":"","sources":["../../../../src/transport/tcp-transport.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,uCAAuC,CAAC;AAEpE,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAEhH,eAAO,MAAM,mBAAmB,EAAE,gBAEjC,CAAC;AAEF;;GAEG;AACH,qBAAa,YAAa,YAAW,SAAS;IAYhC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAXpC,OAAO,CAAC,OAAO,CAAC,CAAqB;IACrC,OAAO,CAAC,OAAO,CAAC,CAAqB;IAErC,SAAgB,MAAM,cAAqB;IAC3C,SAAgB,SAAS,cAAqB;IAC9C,SAAgB,MAAM,cAAqB;IAE3C,OAAO,CAAC,UAAU,CAAS;IAE3B,OAAO,CAAC,UAAU,CAAS;gBAEE,OAAO,EAAE,gBAAgB;IAsChD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ9B,MAAM,CAAC,EAAE,OAAO,EAAE,EAAE,MAAM;IAWpB,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAS7B,QAAQ,IAAI,OAAO,CAAC,cAAc,CAAC;IASzC,OAAO,CAAC,aAAa;CAiBtB"}
@@ -1,6 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  import { type Event } from '@dxos/async';
3
3
  import { type ErrorStream } from '@dxos/debug';
4
+ import { type PublicKey } from '@dxos/keys';
4
5
  import { type Signal } from '@dxos/protocols/proto/dxos/mesh/swarm';
5
6
  export declare enum TransportKind {
6
7
  SIMPLE_PEER = "SIMPLE_PEER",
@@ -16,6 +17,14 @@ export interface Transport {
16
17
  closed: Event;
17
18
  connected: Event;
18
19
  errors: ErrorStream;
20
+ /**
21
+ * Transport-specfic stats.
22
+ */
23
+ getStats(): Promise<TransportStats>;
24
+ /**
25
+ * Transport-specfic connection details.
26
+ */
27
+ getDetails(): Promise<string>;
19
28
  destroy(): Promise<void>;
20
29
  signal(signal: Signal): void;
21
30
  }
@@ -33,6 +42,7 @@ export type TransportOptions = {
33
42
  */
34
43
  sendSignal: (signal: Signal) => Promise<void>;
35
44
  timeout?: number;
45
+ sessionId?: PublicKey;
36
46
  };
37
47
  /**
38
48
  *
@@ -40,4 +50,11 @@ export type TransportOptions = {
40
50
  export interface TransportFactory {
41
51
  createTransport(options: TransportOptions): Transport;
42
52
  }
53
+ export type TransportStats = {
54
+ bytesSent: number;
55
+ bytesReceived: number;
56
+ packetsSent: number;
57
+ packetsReceived: number;
58
+ rawStats?: any;
59
+ };
43
60
  //# sourceMappingURL=transport.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../../../src/transport/transport.ts"],"names":[],"mappings":";AAIA,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,uCAAuC,CAAC;AAEpE,oBAAY,aAAa;IACvB,WAAW,gBAAgB;IAC3B,cAAc,mBAAmB;IACjC,iBAAiB,sBAAsB;IACvC,MAAM,WAAW;IACjB,GAAG,QAAQ;CACZ;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,KAAK,CAAC;IACd,SAAS,EAAE,KAAK,CAAC;IACjB,MAAM,EAAE,WAAW,CAAC;IAEpB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B;;OAEG;IACH,SAAS,EAAE,OAAO,CAAC;IAEnB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC,eAAe,CAAC;IAE/B;;OAEG;IACH,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,CAAC;CACvD"}
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../../../src/transport/transport.ts"],"names":[],"mappings":";AAIA,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,uCAAuC,CAAC;AAEpE,oBAAY,aAAa;IACvB,WAAW,gBAAgB;IAC3B,cAAc,mBAAmB;IACjC,iBAAiB,sBAAsB;IACvC,MAAM,WAAW;IACjB,GAAG,QAAQ;CACZ;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,KAAK,CAAC;IACd,SAAS,EAAE,KAAK,CAAC;IACjB,MAAM,EAAE,WAAW,CAAC;IAEpB;;OAEG;IACH,QAAQ,IAAI,OAAO,CAAC,cAAc,CAAC,CAAC;IACpC;;OAEG;IACH,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B;;OAEG;IACH,SAAS,EAAE,OAAO,CAAC;IAEnB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC,eAAe,CAAC;IAE/B;;OAEG;IACH,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9C,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,CAAC;CACvD;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,GAAG,CAAC;CAChB,CAAC"}
@@ -15,7 +15,7 @@ export type WireProtocolProvider = (params: WireProtocolParams) => WireProtocol;
15
15
  */
16
16
  export interface WireProtocol {
17
17
  stream: Duplex;
18
- open(): Promise<void>;
18
+ open(sessionId?: PublicKey): Promise<void>;
19
19
  close(): Promise<void>;
20
20
  abort(): Promise<void>;
21
21
  }
@@ -1 +1 @@
1
- {"version":3,"file":"wire-protocol.d.ts","sourceRoot":"","sources":["../../../src/wire-protocol.ts"],"names":[],"mappings":";AAIA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,MAAM,MAAM,kBAAkB,GAAG;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,SAAS,CAAC;IACvB,YAAY,EAAE,SAAS,CAAC;IACxB,KAAK,EAAE,SAAS,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,CAAC,MAAM,EAAE,kBAAkB,KAAK,YAAY,CAAC;AAEhF;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IAEf,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,4BACf,QAAQ,KAAK,QAAQ,IAAI,CAAC,KAClD,oBAiBF,CAAC"}
1
+ {"version":3,"file":"wire-protocol.d.ts","sourceRoot":"","sources":["../../../src/wire-protocol.ts"],"names":[],"mappings":";AAIA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,MAAM,MAAM,kBAAkB,GAAG;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,SAAS,CAAC;IACvB,YAAY,EAAE,SAAS,CAAC;IACxB,KAAK,EAAE,SAAS,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,CAAC,MAAM,EAAE,kBAAkB,KAAK,YAAY,CAAC;AAEhF;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IAEf,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,4BACf,QAAQ,KAAK,QAAQ,IAAI,CAAC,KAClD,oBAiBF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/network-manager",
3
- "version": "0.3.9-main.b7e6a67",
3
+ "version": "0.3.9-main.c7cd0ec",
4
4
  "description": "Network Manager",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -24,28 +24,28 @@
24
24
  "@koush/wrtc": "^0.5.3",
25
25
  "isomorphic-ws": "^4.0.1",
26
26
  "nanomessage-rpc": "^3.0.0",
27
- "node-datachannel": "^0.4.3",
27
+ "node-datachannel": "^0.5.2",
28
28
  "p-defer": "^3.0.0",
29
29
  "simple-peer": "9.11.1",
30
30
  "stream": "^0.0.2",
31
31
  "tiny-invariant": "^1.3.1",
32
32
  "ws": "^8.14.2",
33
33
  "xor-distance": "^2.0.0",
34
- "@dxos/async": "0.3.9-main.b7e6a67",
35
- "@dxos/codec-protobuf": "0.3.9-main.b7e6a67",
36
- "@dxos/context": "0.3.9-main.b7e6a67",
37
- "@dxos/credentials": "0.3.9-main.b7e6a67",
38
- "@dxos/crypto": "0.3.9-main.b7e6a67",
39
- "@dxos/debug": "0.3.9-main.b7e6a67",
40
- "@dxos/invariant": "0.3.9-main.b7e6a67",
41
- "@dxos/keys": "0.3.9-main.b7e6a67",
42
- "@dxos/log": "0.3.9-main.b7e6a67",
43
- "@dxos/messaging": "0.3.9-main.b7e6a67",
44
- "@dxos/node-std": "0.3.9-main.b7e6a67",
45
- "@dxos/protocols": "0.3.9-main.b7e6a67",
46
- "@dxos/rpc": "0.3.9-main.b7e6a67",
47
- "@dxos/teleport": "0.3.9-main.b7e6a67",
48
- "@dxos/util": "0.3.9-main.b7e6a67"
34
+ "@dxos/async": "0.3.9-main.c7cd0ec",
35
+ "@dxos/context": "0.3.9-main.c7cd0ec",
36
+ "@dxos/codec-protobuf": "0.3.9-main.c7cd0ec",
37
+ "@dxos/credentials": "0.3.9-main.c7cd0ec",
38
+ "@dxos/crypto": "0.3.9-main.c7cd0ec",
39
+ "@dxos/debug": "0.3.9-main.c7cd0ec",
40
+ "@dxos/invariant": "0.3.9-main.c7cd0ec",
41
+ "@dxos/keys": "0.3.9-main.c7cd0ec",
42
+ "@dxos/log": "0.3.9-main.c7cd0ec",
43
+ "@dxos/messaging": "0.3.9-main.c7cd0ec",
44
+ "@dxos/node-std": "0.3.9-main.c7cd0ec",
45
+ "@dxos/protocols": "0.3.9-main.c7cd0ec",
46
+ "@dxos/rpc": "0.3.9-main.c7cd0ec",
47
+ "@dxos/teleport": "0.3.9-main.c7cd0ec",
48
+ "@dxos/util": "0.3.9-main.c7cd0ec"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@swc-node/register": "1.5.4",
@@ -55,7 +55,7 @@
55
55
  "earljs": "~0.1.10",
56
56
  "fast-check": "~3.3.0",
57
57
  "typescript": "^5.2.2",
58
- "@dxos/signal": "0.3.9-main.b7e6a67"
58
+ "@dxos/signal": "0.3.9-main.c7cd0ec"
59
59
  },
60
60
  "publishConfig": {
61
61
  "access": "public"
@@ -64,7 +64,7 @@ export class ConnectionLog {
64
64
  info.connections!.push(connectionInfo);
65
65
  this.update.emit();
66
66
 
67
- connection.stateChanged.on((state) => {
67
+ connection.stateChanged.on(async (state) => {
68
68
  connectionInfo.state = state;
69
69
  connectionInfo.closeReason = connection.closeReason;
70
70
  connectionInfo.lastUpdate = new Date();
@@ -72,6 +72,12 @@ export class ConnectionLog {
72
72
  type: EventType.CONNECTION_STATE_CHANGED,
73
73
  newState: state,
74
74
  });
75
+
76
+ if (state === ConnectionState.CONNECTED) {
77
+ const details = await connection.transport?.getDetails();
78
+ connectionInfo.transportDetails = details;
79
+ }
80
+
75
81
  this.update.emit();
76
82
  });
77
83
 
@@ -83,6 +89,13 @@ export class ConnectionLog {
83
89
  this.update.emit();
84
90
  });
85
91
 
92
+ connection.transportStats?.on((stats) => {
93
+ connectionInfo.transportBytesSent = stats.bytesSent;
94
+ connectionInfo.transportBytesReceived = stats.bytesReceived;
95
+ connectionInfo.transportPacketsSent = stats.packetsSent;
96
+ connectionInfo.transportPacketsReceived = stats.packetsReceived;
97
+ });
98
+
86
99
  gcSwarm(info);
87
100
 
88
101
  // connection.protocol.protocol?.error.on((error) => {
@@ -2,24 +2,25 @@
2
2
  // Copyright 2021 DXOS.org
3
3
  //
4
4
 
5
- import { DeferredTask, Event, sleep, scheduleTask, synchronized } from '@dxos/async';
5
+ import { DeferredTask, Event, sleep, scheduleTask, scheduleTaskInterval, synchronized } from '@dxos/async';
6
6
  import { Context, cancelWithContext } from '@dxos/context';
7
7
  import { ErrorStream } from '@dxos/debug';
8
8
  import { invariant } from '@dxos/invariant';
9
9
  import { PublicKey } from '@dxos/keys';
10
- import { log } from '@dxos/log';
10
+ import { log, logInfo } from '@dxos/log';
11
11
  import {
12
12
  CancelledError,
13
13
  ProtocolError,
14
14
  ConnectionResetError,
15
15
  ConnectivityError,
16
+ TimeoutError,
16
17
  UnknownProtocolError,
17
18
  trace,
18
19
  } from '@dxos/protocols';
19
20
  import { type Signal } from '@dxos/protocols/proto/dxos/mesh/swarm';
20
21
 
21
22
  import { type SignalMessage, type SignalMessenger } from '../signal';
22
- import { type Transport, type TransportFactory } from '../transport';
23
+ import { type Transport, type TransportFactory, type TransportStats } from '../transport';
23
24
  import { type WireProtocol } from '../wire-protocol';
24
25
 
25
26
  /**
@@ -33,6 +34,8 @@ const STARTING_SIGNALLING_DELAY = 10;
33
34
  */
34
35
  const TRANSPORT_CONNECTION_TIMEOUT = 10_000;
35
36
 
37
+ const TRANSPORT_STATS_INTERVAL = 5_000;
38
+
36
39
  /**
37
40
  * Maximum delay between signal batches.
38
41
  */
@@ -109,6 +112,8 @@ export class Connection {
109
112
 
110
113
  public _instanceId = PublicKey.random().toHex();
111
114
 
115
+ public readonly transportStats = new Event<TransportStats>();
116
+
112
117
  private readonly _signalSendTask = new DeferredTask(this._ctx, async () => {
113
118
  await this._flushSignalBuffer();
114
119
  });
@@ -135,6 +140,11 @@ export class Connection {
135
140
  });
136
141
  }
137
142
 
143
+ @logInfo
144
+ get sessionIdString(): string {
145
+ return this.sessionId.truncate();
146
+ }
147
+
138
148
  get state() {
139
149
  return this._state;
140
150
  }
@@ -164,7 +174,7 @@ export class Connection {
164
174
  this._changeState(ConnectionState.CONNECTING);
165
175
 
166
176
  // TODO(dmaretskyi): Initialize only after the transport has established connection.
167
- this._protocol.open().catch((err) => {
177
+ this._protocol.open(this.sessionId).catch((err) => {
168
178
  this.errors.raise(err);
169
179
  });
170
180
 
@@ -177,8 +187,10 @@ export class Connection {
177
187
  scheduleTask(
178
188
  this.connectedTimeoutContext,
179
189
  async () => {
180
- log.info('timeout waiting for transport to connect, aborting');
181
- await this.abort().catch((err) => this.errors.raise(err));
190
+ log.info(`timeout waiting ${TRANSPORT_CONNECTION_TIMEOUT / 1000}s for transport to connect, aborting`);
191
+ await this.abort(new TimeoutError(`${TRANSPORT_CONNECTION_TIMEOUT / 1000}s for transport to connect`)).catch(
192
+ (err) => this.errors.raise(err),
193
+ );
182
194
  },
183
195
  TRANSPORT_CONNECTION_TIMEOUT,
184
196
  );
@@ -188,12 +200,15 @@ export class Connection {
188
200
  initiator: this.initiator,
189
201
  stream: this._protocol.stream,
190
202
  sendSignal: async (signal) => this._sendSignal(signal),
203
+ sessionId: this.sessionId,
191
204
  });
192
205
 
193
206
  this._transport.connected.once(async () => {
194
207
  this._changeState(ConnectionState.CONNECTED);
195
208
  await this.connectedTimeoutContext.dispose();
196
209
  this._callbacks?.onConnected?.();
210
+
211
+ scheduleTaskInterval(this._ctx, async () => this._emitTransportStats(), TRANSPORT_STATS_INTERVAL);
197
212
  });
198
213
 
199
214
  this._transport.closed.once(() => {
@@ -312,6 +327,18 @@ export class Connection {
312
327
  } catch (err: any) {
313
328
  log.catch(err);
314
329
  }
330
+ } else {
331
+ log.info(`graceful close requested when we were in ${lastState} state? aborting`);
332
+ try {
333
+ await this._protocol.abort();
334
+ } catch (err: any) {
335
+ log.catch(err);
336
+ }
337
+ try {
338
+ await this._transport?.destroy();
339
+ } catch (err: any) {
340
+ log.catch(err);
341
+ }
315
342
  }
316
343
 
317
344
  log('closed', { peerId: this.ownId });
@@ -397,4 +424,11 @@ export class Connection {
397
424
  this._state = state;
398
425
  this.stateChanged.emit(state);
399
426
  }
427
+
428
+ private async _emitTransportStats() {
429
+ const stats = await this.transport?.getStats();
430
+ if (stats) {
431
+ this.transportStats.emit(stats);
432
+ }
433
+ }
400
434
  }
@@ -10,6 +10,9 @@ import { log } from '@dxos/log';
10
10
 
11
11
  import { type SwarmController, type Topology } from './topology';
12
12
 
13
+ const MIN_UPDATE_INTERVAL = 1000 * 10;
14
+ const MAX_CHANGES_PER_UPDATE = 1;
15
+
13
16
  export interface MMSTTopologyOptions {
14
17
  /**
15
18
  * Number of connections the peer will originate by itself.
@@ -36,6 +39,8 @@ export class MMSTTopology implements Topology {
36
39
 
37
40
  private _sampleCollected = false;
38
41
 
42
+ private _lastAction = new Date(0);
43
+
39
44
  constructor({ originateConnections = 2, maxPeers = 4, sampleSize = 10 }: MMSTTopologyOptions = {}) {
40
45
  this._originateConnections = originateConnections;
41
46
  this._maxPeers = maxPeers;
@@ -74,22 +79,45 @@ export class MMSTTopology implements Topology {
74
79
  invariant(this._controller, 'Not initialized');
75
80
  const { connected, candidates, ownPeerId } = this._controller.getState();
76
81
 
82
+ // TODO(nf): does this rate limiting/flap dampening logic belong here or in the SwarmController?
77
83
  if (connected.length > this._maxPeers) {
78
84
  // Disconnect extra peers.
85
+ log(`disconnect ${connected.length - this._maxPeers} peers.`);
79
86
  const sorted = sortByXorDistance(connected, ownPeerId)
80
87
  .reverse()
81
88
  .slice(0, this._maxPeers - connected.length);
82
- for (const peer of sorted) {
83
- log(`Disconnect ${peer}.`);
84
- this._controller.disconnect(peer);
89
+ invariant(sorted.length === 0);
90
+
91
+ if (sorted.length > MAX_CHANGES_PER_UPDATE) {
92
+ log(`want to disconnect ${sorted.length} peers but limited to ${MAX_CHANGES_PER_UPDATE}`);
93
+ }
94
+
95
+ if (Date.now() - this._lastAction.getTime() > MIN_UPDATE_INTERVAL) {
96
+ for (const peer of sorted.slice(0, MAX_CHANGES_PER_UPDATE)) {
97
+ log(`Disconnect ${peer}.`);
98
+ this._controller.disconnect(peer);
99
+ }
100
+ this._lastAction = new Date();
101
+ } else {
102
+ log('rate limited discconnect');
85
103
  }
86
104
  } else if (connected.length < this._originateConnections) {
87
105
  // Connect new peers to reach desired quota.
106
+ log(`connect ${this._originateConnections - connected.length} peers.`);
88
107
  const sample = candidates.sort(() => Math.random() - 0.5).slice(0, this._sampleSize);
89
108
  const sorted = sortByXorDistance(sample, ownPeerId).slice(0, this._originateConnections - connected.length);
90
- for (const peer of sorted) {
91
- log(`Connect ${peer}.`);
92
- this._controller.connect(peer);
109
+
110
+ if (sorted.length > MAX_CHANGES_PER_UPDATE) {
111
+ log(`want to connect ${sorted.length} peers but limited to ${MAX_CHANGES_PER_UPDATE}`);
112
+ }
113
+ if (Date.now() - this._lastAction.getTime() > MIN_UPDATE_INTERVAL) {
114
+ for (const peer of sorted.slice(0, MAX_CHANGES_PER_UPDATE)) {
115
+ log(`Connect ${peer}.`);
116
+ this._controller.connect(peer);
117
+ }
118
+ this._lastAction = new Date();
119
+ } else {
120
+ log('rate limited connect');
93
121
  }
94
122
  }
95
123
  }
@@ -7,6 +7,5 @@ export * from './transport';
7
7
  export * from './simplepeer-transport';
8
8
  export * from './simplepeer-transport-service';
9
9
  export * from './simplepeer-transport-proxy';
10
- export * from './datachannel';
11
10
  export * from './libdatachannel-transport';
12
11
  export * from './tcp-transport';
@@ -2,10 +2,6 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- //
6
- // Copyright 2020 DXOS.org
7
- //
8
-
9
5
  import { Duplex } from 'stream';
10
6
 
11
7
  import { sleep, TestStream } from '@dxos/async';
@@ -9,8 +9,7 @@ import { ErrorStream } from '@dxos/debug';
9
9
  import { log } from '@dxos/log';
10
10
  import { type Signal } from '@dxos/protocols/proto/dxos/mesh/swarm';
11
11
 
12
- import { type PeerConnection } from './datachannel/rtc-peer-connection';
13
- import { type Transport, type TransportFactory } from './transport';
12
+ import { type Transport, type TransportFactory, type TransportStats } from './transport';
14
13
 
15
14
  export type LibDataChannelTransportParams = {
16
15
  initiator: boolean;
@@ -34,7 +33,7 @@ export class LibDataChannelTransport implements Transport {
34
33
  private _connected = false;
35
34
  readonly connected = new Event();
36
35
  readonly errors = new ErrorStream();
37
- private readonly _peer: Promise<PeerConnection>;
36
+ private readonly _peer: Promise<RTCPeerConnection>;
38
37
  private _channel!: RTCDataChannel;
39
38
  private _stream!: Duplex;
40
39
 
@@ -43,11 +42,20 @@ export class LibDataChannelTransport implements Transport {
43
42
 
44
43
  constructor(private readonly params: LibDataChannelTransportParams) {
45
44
  this._peer = (async () => {
46
- const { RTCPeerConnection: PeerConnection } = await import('./datachannel');
45
+ /* eslint-disable @typescript-eslint/consistent-type-imports */
46
+ const { RTCPeerConnection } = (await importESM('node-datachannel/polyfill'))
47
+ .default as typeof import('node-datachannel/polyfill');
48
+ /* eslint-enable @typescript-eslint/consistent-type-imports */
47
49
  if (this._closed) {
48
50
  this.errors.raise(new Error('connection already closed'));
49
51
  }
50
- const peer = new PeerConnection(params.webrtcConfig);
52
+ // workaround https://github.com/murat-dogan/node-datachannel/pull/207
53
+ if (params.webrtcConfig) {
54
+ params.webrtcConfig.iceServers = params.webrtcConfig.iceServers ?? [];
55
+ } else {
56
+ params.webrtcConfig = { iceServers: [] };
57
+ }
58
+ const peer = new RTCPeerConnection(params.webrtcConfig);
51
59
 
52
60
  peer.onicecandidateerror = (event) => {
53
61
  log.error('peer.onicecandidateerror', { event });
@@ -84,10 +92,14 @@ export class LibDataChannelTransport implements Transport {
84
92
  }
85
93
  }
86
94
  };
95
+
87
96
  if (params.initiator) {
88
97
  peer
89
98
  .createOffer()
90
99
  .then(async (offer) => {
100
+ if (this._closed) {
101
+ return;
102
+ }
91
103
  if (peer.connectionState !== 'connecting') {
92
104
  log.error('i am initiator but peer not in state connecting', { peer });
93
105
  this.errors.raise(new Error('invalid state: peer is initiator, but other peer not in state connecting'));
@@ -126,14 +138,18 @@ export class LibDataChannelTransport implements Transport {
126
138
  log.debug('dataChannel.onopen');
127
139
  const duplex = new Duplex({
128
140
  read: () => {},
129
- write: (chunk, encoding, callback) => {
141
+ write: async (chunk, encoding, callback) => {
130
142
  // todo wait to open
131
143
 
132
144
  if (chunk.length > MAX_MESSAGE_SIZE) {
133
145
  this.errors.raise(new Error(`message too large: ${chunk.length} > ${MAX_MESSAGE_SIZE}`));
134
146
  }
135
- dataChannel.send(chunk);
136
-
147
+ try {
148
+ dataChannel.send(chunk);
149
+ } catch (err: any) {
150
+ this.errors.raise(err);
151
+ await this._close();
152
+ }
137
153
  if (this._channel.bufferedAmount > MAX_BUFFERED_AMOUNT) {
138
154
  if (this._writeCallback !== null) {
139
155
  log.error("consumer trying to write before we're ready for more data");
@@ -180,6 +196,12 @@ export class LibDataChannelTransport implements Transport {
180
196
  return;
181
197
  }
182
198
  await this._disconnectStreams();
199
+ const peer = await this._peer;
200
+ try {
201
+ peer.close();
202
+ } catch (err: any) {
203
+ this.errors.raise(err);
204
+ }
183
205
  this._closed = true;
184
206
  this.closed.emit();
185
207
  }
@@ -233,6 +255,63 @@ export class LibDataChannelTransport implements Transport {
233
255
  });
234
256
  }
235
257
 
258
+ async getDetails(): Promise<string> {
259
+ const stats = await this._getStats();
260
+ const rc = stats?.remoteCandidate;
261
+ if (!rc) {
262
+ return 'unavailable';
263
+ }
264
+
265
+ if (rc.candidateType === 'relay') {
266
+ return `${rc.ip}:${rc.port} relay for ${rc.relatedAddress}:${rc.relatedPort}`;
267
+ }
268
+ return `${rc.ip}:${rc.port} ${rc.candidateType}`;
269
+ }
270
+
271
+ async _getStats(): Promise<any> {
272
+ return this._peer.then(async (peer) => {
273
+ const stats = await peer.getStats();
274
+
275
+ const statsEntries = Array.from((stats as any).entries() as any[]);
276
+ const transport = statsEntries.filter((s) => s[1].type === 'transport')[0][1];
277
+ const candidatePair = statsEntries.filter((s: any) => s[0] === transport.selectedCandidatePairId);
278
+ let selectedCandidatePair: any;
279
+ let remoteCandidate: any;
280
+ if (candidatePair.length > 0) {
281
+ selectedCandidatePair = candidatePair[0][1];
282
+ remoteCandidate = statsEntries.filter((s: any) => s[0] === selectedCandidatePair.remoteCandidateId)[0][1];
283
+ }
284
+
285
+ return {
286
+ transport,
287
+ selectedCandidatePair,
288
+ remoteCandidate,
289
+ raw: Object.fromEntries(stats as any),
290
+ };
291
+ });
292
+ }
293
+
294
+ async getStats(): Promise<TransportStats> {
295
+ const stats = await this._getStats();
296
+ if (!stats) {
297
+ return {
298
+ bytesSent: 0,
299
+ bytesReceived: 0,
300
+ packetsSent: 0,
301
+ packetsReceived: 0,
302
+ rawStats: {},
303
+ };
304
+ }
305
+
306
+ return {
307
+ bytesSent: stats.transport.bytesSent,
308
+ bytesReceived: stats.transport.bytesReceived,
309
+ packetsSent: 0,
310
+ packetsReceived: 0,
311
+ rawStats: stats.raw,
312
+ };
313
+ }
314
+
236
315
  // TODO(nf): add classmethod to call node-datachannel.cleanup() when all instances have been destroyed?
237
316
  async destroy(): Promise<void> {
238
317
  await this._close();
@@ -250,3 +329,6 @@ export const createLibDataChannelTransportFactory = (webrtcConfig?: any): Transp
250
329
  webrtcConfig,
251
330
  }),
252
331
  });
332
+
333
+ // eslint-disable-next-line no-new-func
334
+ const importESM = Function('path', 'return import(path)');
@@ -12,7 +12,7 @@ import { log, logInfo } from '@dxos/log';
12
12
  import { type Signal } from '@dxos/protocols/proto/dxos/mesh/swarm';
13
13
  import { ComplexMap } from '@dxos/util';
14
14
 
15
- import { type Transport, type TransportFactory, type TransportOptions } from './transport';
15
+ import { type Transport, type TransportFactory, type TransportOptions, type TransportStats } from './transport';
16
16
 
17
17
  // TODO(burdon): Make configurable.
18
18
  // Delay (in milliseconds) for data being sent through in-memory connections to simulate network latency.
@@ -166,4 +166,17 @@ export class MemoryTransport implements Transport {
166
166
  this._remote.wake(remoteId);
167
167
  }
168
168
  }
169
+
170
+ async getDetails(): Promise<string> {
171
+ return this._instanceId.toHex();
172
+ }
173
+
174
+ async getStats(): Promise<TransportStats> {
175
+ return {
176
+ bytesSent: 0,
177
+ bytesReceived: 0,
178
+ packetsSent: 0,
179
+ packetsReceived: 0,
180
+ };
181
+ }
169
182
  }