@fails-components/webtransport 0.2.2 → 0.3.0

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 (101) hide show
  1. package/CMakeLists.txt +3 -0
  2. package/dist/lib/client.d.ts +7 -3
  3. package/dist/lib/client.d.ts.map +1 -1
  4. package/dist/lib/dom.d.ts +15 -4
  5. package/dist/lib/dom.d.ts.map +1 -1
  6. package/dist/lib/error.d.ts +8 -0
  7. package/dist/lib/error.d.ts.map +1 -0
  8. package/dist/lib/event-loop.d.ts +4 -2
  9. package/dist/lib/event-loop.d.ts.map +1 -1
  10. package/dist/lib/native.d.ts.map +1 -1
  11. package/dist/lib/server.d.ts +5 -2
  12. package/dist/lib/server.d.ts.map +1 -1
  13. package/dist/lib/session.d.ts +36 -23
  14. package/dist/lib/session.d.ts.map +1 -1
  15. package/dist/lib/stream.d.ts +15 -4
  16. package/dist/lib/stream.d.ts.map +1 -1
  17. package/dist/lib/transport.d.ts +12 -3
  18. package/dist/lib/transport.d.ts.map +1 -1
  19. package/dist/lib/types.d.ts +43 -4
  20. package/dist/lib/types.d.ts.map +1 -1
  21. package/dist/lib/utils.d.ts +5 -0
  22. package/dist/lib/utils.d.ts.map +1 -1
  23. package/dist/lib/webtransport.d.ts +11 -21
  24. package/dist/lib/webtransport.d.ts.map +1 -1
  25. package/dist/test/datagrams.spec.d.ts.map +1 -1
  26. package/dist/test/event-loop.node.d.ts +2 -0
  27. package/dist/test/event-loop.node.d.ts.map +1 -0
  28. package/dist/test/fixtures/chai.d.ts.map +1 -1
  29. package/dist/test/fixtures/known-bytes.d.ts +6 -0
  30. package/dist/test/fixtures/known-bytes.d.ts.map +1 -0
  31. package/dist/test/fixtures/read-cert-hash.d.ts +6 -0
  32. package/dist/test/fixtures/read-cert-hash.d.ts.map +1 -0
  33. package/dist/test/fixtures/read-stream.d.ts +10 -1
  34. package/dist/test/fixtures/read-stream.d.ts.map +1 -1
  35. package/dist/test/fixtures/reader-value.d.ts +16 -1
  36. package/dist/test/fixtures/reader-value.d.ts.map +1 -1
  37. package/dist/test/fixtures/server.d.ts +0 -5
  38. package/dist/test/fixtures/server.d.ts.map +1 -1
  39. package/dist/test/fixtures/webtransport.browser.d.ts +3 -0
  40. package/dist/test/fixtures/webtransport.browser.d.ts.map +1 -0
  41. package/dist/test/fixtures/webtransport.d.ts +3 -0
  42. package/dist/test/fixtures/webtransport.d.ts.map +1 -0
  43. package/dist/test/fixtures/write-stream.d.ts.map +1 -1
  44. package/dist/test/index.d.ts +2 -0
  45. package/dist/test/index.d.ts.map +1 -0
  46. package/dist/test/session.spec.d.ts +5 -0
  47. package/dist/test/session.spec.d.ts.map +1 -0
  48. package/dist/test/unidirectional-streams.spec.d.ts +1 -4
  49. package/dist/test/unidirectional-streams.spec.d.ts.map +1 -1
  50. package/lib/client.js +57 -43
  51. package/lib/dom.ts +18 -4
  52. package/lib/error.js +10 -0
  53. package/lib/event-loop.js +8 -5
  54. package/lib/native.js +4 -1
  55. package/lib/server.js +18 -10
  56. package/lib/session.js +145 -32
  57. package/lib/stream.js +51 -22
  58. package/lib/transport.js +48 -10
  59. package/lib/types.ts +53 -5
  60. package/lib/utils.js +13 -0
  61. package/lib/webtransport.js +10 -18
  62. package/{test → old_test}/echoserver.js +1 -2
  63. package/{test → old_test}/test.js +5 -3
  64. package/package.json +16 -5
  65. package/readme.md +64 -0
  66. package/src/http3client.cc +2 -2
  67. package/src/http3dispatcher.cc +3 -2
  68. package/src/http3dispatcher.h +2 -1
  69. package/src/http3eventloop.cc +106 -2
  70. package/src/http3eventloop.h +13 -0
  71. package/src/http3wtsessionvisitor.cc +2 -0
  72. package/src/http3wtsessionvisitor.h +41 -1
  73. package/test/bidirectional-streams.spec.js +41 -97
  74. package/test/datagrams.spec.js +50 -99
  75. package/test/fixtures/chai.js +2 -0
  76. package/test/fixtures/known-bytes.js +15 -0
  77. package/test/fixtures/read-cert-hash.js +7 -0
  78. package/test/fixtures/read-stream.js +5 -0
  79. package/test/fixtures/reader-value.js +32 -0
  80. package/test/fixtures/server.js +237 -21
  81. package/test/fixtures/webtransport.browser.js +2 -0
  82. package/test/fixtures/webtransport.js +3 -0
  83. package/test/fixtures/write-stream.js +8 -1
  84. package/test/index.js +87 -0
  85. package/test/session.spec.js +159 -0
  86. package/test/unidirectional-streams.spec.js +67 -138
  87. package/tsconfig.json +0 -1
  88. package/dist/test/echoclient.d.ts +0 -2
  89. package/dist/test/echoclient.d.ts.map +0 -1
  90. package/dist/test/echoserver.d.ts +0 -2
  91. package/dist/test/echoserver.d.ts.map +0 -1
  92. package/dist/test/event-loop.spec.d.ts +0 -2
  93. package/dist/test/event-loop.spec.d.ts.map +0 -1
  94. package/dist/test/test.d.ts +0 -2
  95. package/dist/test/test.d.ts.map +0 -1
  96. package/dist/test/testsuite.d.ts +0 -25
  97. package/dist/test/testsuite.d.ts.map +0 -1
  98. package/platform/base/strings/utf_ostream_operators.h +0 -5
  99. /package/{test → old_test}/echoclient.js +0 -0
  100. /package/{test → old_test}/testsuite.js +0 -0
  101. /package/test/{event-loop.spec.js → event-loop.node.js} +0 -0
package/lib/utils.js CHANGED
@@ -1,3 +1,5 @@
1
+ import debug from 'debug'
2
+
1
3
  /**
2
4
  * @template {unknown} T
3
5
  * @returns {import('./types').Deferred<T>}
@@ -20,3 +22,14 @@ export function defer() {
20
22
  reject: rej
21
23
  }
22
24
  }
25
+
26
+ /**
27
+ * @param {string} name
28
+ * @returns {import('./types').Logger}
29
+ */
30
+ export function logger(name) {
31
+ return Object.assign(debug(name), {
32
+ error: debug(`${name}:error`),
33
+ trace: process.env.DEBUG_TRACE ? debug(`${name}:trace`) : () => {}
34
+ })
35
+ }
@@ -10,6 +10,11 @@ const sessions = new WeakMap()
10
10
  * @typedef {import('./dom').WebTransportReceiveStream} WebTransportReceiveStream
11
11
  */
12
12
 
13
+ /**
14
+ * @template T
15
+ * @typedef {import('node:stream/web').ReadableStream<T>} ReadableStream<T>
16
+ */
17
+
13
18
  /**
14
19
  * @typedef {import('./dom').WebTransport} WebTransportInterface
15
20
  *
@@ -29,11 +34,11 @@ export class WebTransport {
29
34
  throw new Error('URL is not supported for webtransport')
30
35
  }
31
36
 
32
- const hostname = ourl.hostname
37
+ const host = ourl.hostname
33
38
  let port = ourl.port
34
39
  if (port === '') port = '443'
35
40
 
36
- const client = new Http3Client({ hostname, port, ...args })
41
+ const client = new Http3Client({ host, port, ...args })
37
42
 
38
43
  const sessionint = new Http3WTSession({
39
44
  /* object: args.session, */
@@ -49,7 +54,6 @@ export class WebTransport {
49
54
  /** @type {ReadableStream<WebTransportBidirectionalStream>} */
50
55
  this.incomingBidirectionalStreams = sessionint.incomingBidirectionalStreams
51
56
 
52
- /** @type {ReadableStream<WebTransportReceiveStream>} */
53
57
  this.incomingUnidirectionalStreams =
54
58
  sessionint.incomingUnidirectionalStreams
55
59
 
@@ -57,23 +61,11 @@ export class WebTransport {
57
61
 
58
62
  client
59
63
  .handleConnection()
60
- .then(() => {
61
- client.quicconnected
62
- ?.then(() => {
63
- return client.createWTSession(sessionint, ourl.pathname)
64
- })
65
- .catch((err) => {
66
- sessionint.readyReject(
67
- new Error('Establishing session failed ' + err)
68
- )
69
- console.log('Establishing session failed ' + err)
70
- client.closeHookSession()
71
- })
72
- })
64
+ .then(() => client.createWTSession(sessionint, ourl.pathname))
73
65
  .catch((error) => {
74
- sessionint.readyReject(new Error('Quic connection failed ' + error))
75
- console.log('Quic connection failed ' + error)
76
66
  client.closeHookSession()
67
+ sessionint.readyReject(error)
68
+ sessionint.closedReject(error)
77
69
  })
78
70
  }
79
71
 
@@ -5,8 +5,7 @@
5
5
  import { Http3Server } from '../lib/index.js'
6
6
  import { runEchoServer } from './testsuite.js'
7
7
  import { existsSync, readFileSync, writeFile } from 'node:fs'
8
- // @ts-ignore
9
- import { generateWebTransportCertificate } from './fixtures/certificate.js'
8
+ import { generateWebTransportCertificate } from '../test/fixtures/certificate.js'
10
9
 
11
10
  let certificate = null
12
11
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  // this file runs various tests
6
6
 
7
- import { generateWebTransportCertificate } from './fixtures/certificate.js'
7
+ import { generateWebTransportCertificate } from '../test/fixtures/certificate.js'
8
8
  import { Http3Server, WebTransport, testcheck } from '../lib/index.js'
9
9
  import { echoTestsConnection, runEchoServer } from './testsuite.js'
10
10
 
@@ -30,7 +30,7 @@ async function run() {
30
30
  }
31
31
  ]
32
32
  })
33
- await badClient.ready
33
+ await Promise.all([badClient.ready, badClient.closed])
34
34
  .then(() => {
35
35
  console.error('Successfully connected to a non-running server?!')
36
36
  process.exit(1)
@@ -67,8 +67,8 @@ async function run() {
67
67
  privKey: certificate.private
68
68
  })
69
69
 
70
- runEchoServer(http3server)
71
70
  http3server.startServer() // you can call destroy to remove the server
71
+ runEchoServer(http3server)
72
72
 
73
73
  console.log('server started now wait 2 seconds')
74
74
 
@@ -98,6 +98,8 @@ async function run() {
98
98
  await client.ready
99
99
  console.log('client is ready')
100
100
  await echoTestsConnection(client)
101
+ console.log('Test if getStats works')
102
+ console.log('getStats returned', await client.getStats())
101
103
  console.log('client test finished, now close the client but wait 2 seconds')
102
104
 
103
105
  await new Promise((resolve) => setTimeout(resolve, 2000))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fails-components/webtransport",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "description": "A component to add webtransport support (server and client) to node.js using libquiche",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib/index.js",
@@ -11,15 +11,17 @@
11
11
  "types": "./dist/lib/index.d.ts",
12
12
  "scripts": {
13
13
  "start": "node test/echoserver.js",
14
- "test": "mocha test/*.spec.js",
15
- "oldtest": "node test/test.js",
14
+ "test": "npm run test:node && npm run test:chromium",
15
+ "test:node": "node test/index.js node",
16
+ "test:chromium": "node test/index.js chromium",
17
+ "oldtest": "node old_test/test.js",
16
18
  "install": "node build.js install",
17
19
  "build": "node build.js build",
18
20
  "rebuild": "node build.js rebuild",
19
21
  "rebuild-debug": "node build.js rebuild-debug -D",
20
22
  "build-debug": "node build.js build-debug",
21
23
  "types": "tsc",
22
- "lint": "eslint lib test"
24
+ "lint": "eslint lib test old_test"
23
25
  },
24
26
  "repository": {
25
27
  "type": "git",
@@ -35,7 +37,9 @@
35
37
  },
36
38
  "homepage": "https://github.com/fails-components/webtransport#readme",
37
39
  "dependencies": {
40
+ "@types/debug": "^4.1.7",
38
41
  "bindings": "^1.5.0",
42
+ "debug": "^4.3.4",
39
43
  "node-addon-api": "^4.3.0",
40
44
  "prebuild-install": "^7.1.1"
41
45
  },
@@ -43,10 +47,12 @@
43
47
  "@babel/core": "^7.17.10",
44
48
  "@babel/eslint-parser": "^7.17.0",
45
49
  "@types/chai": "^4.3.3",
50
+ "@types/chai-as-promised": "^7.1.5",
46
51
  "@types/dirty-chai": "^2.0.2",
47
52
  "@types/mocha": "^10.0.0",
48
53
  "@types/node": "^18.15.3",
49
54
  "chai": "^4.3.6",
55
+ "chai-as-promised": "^7.1.1",
50
56
  "cmake-js": "^6.3.2",
51
57
  "dirty-chai": "^2.0.1",
52
58
  "eslint": "^7.32.0",
@@ -57,15 +63,20 @@
57
63
  "eslint-plugin-prettier": "^3.4.1",
58
64
  "eslint-plugin-promise": "^4.3.1",
59
65
  "eslint-plugin-standard": "^4.1.0",
66
+ "execa": "^6.1.0",
60
67
  "mocha": "^10.1.0",
61
68
  "node-forge": "^1.3.1",
69
+ "playwright-test": "^12.3.4",
62
70
  "prettier": "^2.4.1",
63
- "typescript": "4.8.4",
71
+ "typescript": "^4.8.4",
64
72
  "uint8arrays": "^4.0.2"
65
73
  },
66
74
  "binary": {
67
75
  "napi_versions": [
68
76
  6
69
77
  ]
78
+ },
79
+ "browser": {
80
+ "./test/fixtures/webtransport.js": "./test/fixtures/webtransport.browser.js"
70
81
  }
71
82
  }
package/readme.md CHANGED
@@ -85,3 +85,67 @@ The WebTransport client only supports certification validation using fingerprint
85
85
  * [outgoingMaxAge](https://www.w3.org/TR/webtransport/#dom-webtransportdatagramduplexstream-outgoingmaxage)
86
86
  * [incomingHighWaterMark](https://www.w3.org/TR/webtransport/#dom-webtransportdatagramduplexstream-incominghighwatermark)
87
87
  * [outgoingHighWaterMark](https://www.w3.org/TR/webtransport/#dom-webtransportdatagramduplexstream-outgoinghighwatermark)
88
+
89
+ ## Development notes
90
+
91
+ ### Tests
92
+
93
+ The unit test suite can be run on both node.js and Chrome to ensure behaviour is consistent between the two environments.
94
+
95
+ [Mocha](https://www.npmjs.com/package/mocha) is used as a test runner in both environments, in the browser it is run via [playwright-test](https://www.npmjs.com/package/playwright-test).
96
+
97
+ #### Running all tests:
98
+
99
+ ```console
100
+ $ npm test
101
+ ```
102
+
103
+ #### Running in node
104
+
105
+ ```console
106
+ $ npm run test:node
107
+ ```
108
+
109
+ #### Running in Chromium
110
+
111
+ ```console
112
+ $ npm run test:chrome
113
+ ```
114
+
115
+ #### Forward args
116
+
117
+ Forward args are supported so you can pass any Mocha or playwright-test options after the `--`:
118
+
119
+ E.g.:
120
+
121
+ Run only "unidirectional streams" tests:
122
+
123
+ ```console
124
+ $ npm run test:node -- --grep '"unidirectional streams"'
125
+ ```
126
+
127
+ Disable headless mode to watch tests run in Chromium:
128
+
129
+ ```console
130
+ $ npm run test:chromium -- --debug
131
+ ```
132
+
133
+ ### Logging
134
+
135
+ This module uses the [debug](https://www.npmjs.com/package/debug) module for logging.
136
+
137
+ To enable logging, specify the `DEBUG` environmental variable:
138
+
139
+ ```console
140
+ $ DEBUG=webtransport* node my-script.js
141
+ // debug output
142
+ ```
143
+
144
+ #### Trace logging
145
+
146
+ To enable detailed output, additionally set the `DEBUG_TRACE` environmental variable:
147
+
148
+ ```console
149
+ $ DEBUG=webtransport* DEBUG_TRACE=true node my-script.js
150
+ // lots of debug output
151
+ ```
@@ -1329,9 +1329,9 @@ namespace quic
1329
1329
  return;
1330
1330
  }
1331
1331
 
1332
- if (lobj.Has("hostname") && !(lobj).Get("hostname").IsEmpty())
1332
+ if (lobj.Has("host") && !(lobj).Get("host").IsEmpty())
1333
1333
  {
1334
- Napi::Value hostnameValue = (lobj).Get("hostname");
1334
+ Napi::Value hostnameValue = (lobj).Get("host");
1335
1335
  hostname = hostnameValue.ToString().Utf8Value();
1336
1336
  }
1337
1337
  else
@@ -43,13 +43,14 @@ std::unique_ptr<QuicSession> Http3Dispatcher::CreateQuicSession(
43
43
  QuicConnectionId connection_id, const QuicSocketAddress& self_address,
44
44
  const QuicSocketAddress& peer_address, absl::string_view /*alpn*/,
45
45
  const ParsedQuicVersion& version,
46
- const ParsedClientHello& /*parsed_chlo*/) {
46
+ const ParsedClientHello& /*parsed_chlo*/,
47
+ ConnectionIdGeneratorInterface& connection_id_generator) {
47
48
  // The QuicServerSessionBase takes ownership of |connection| below.
48
49
  QuicConnection* connection =
49
50
  new QuicConnection(connection_id, self_address, peer_address, helper(),
50
51
  alarm_factory(), writer(),
51
52
  /* owns_writer= */ false, Perspective::IS_SERVER,
52
- ParsedQuicVersionVector{version}, connection_id_generator());
53
+ ParsedQuicVersionVector{version}, connection_id_generator);
53
54
 
54
55
  auto session = std::make_unique<Http3ServerSession>(
55
56
  config(), GetSupportedVersions(), connection, this, session_helper(),
@@ -40,7 +40,8 @@ namespace quic
40
40
  QuicConnectionId connection_id, const QuicSocketAddress &self_address,
41
41
  const QuicSocketAddress &peer_address, absl::string_view alpn,
42
42
  const ParsedQuicVersion &version,
43
- const ParsedClientHello &parsed_chlo) override;
43
+ const ParsedClientHello &parsed_chlo,
44
+ ConnectionIdGeneratorInterface& connection_id_generator) override;
44
45
 
45
46
  Http3ServerBackend *server_backend()
46
47
  {
@@ -33,6 +33,7 @@ namespace quic
33
33
  static const int kErrorBufferSize = 256;
34
34
 
35
35
  const size_t kNumSessionsToCreatePerSocketEvent = 16;
36
+ bool Http3EventLoop::hasSetLogging = false;
36
37
 
37
38
  Http3EventLoop::~Http3EventLoop()
38
39
  {
@@ -220,6 +221,31 @@ namespace quic
220
221
  progress_->Send(&report, 1);
221
222
  }
222
223
 
224
+ void Http3EventLoop::informSessionStats(Http3WTSession *sessionobj, webtransport::SessionStats * sessstats)
225
+ {
226
+ Http3ProgressReport report;
227
+ report.type = Http3ProgressReport::SessionStats;
228
+ report.sessionobj = sessionobj;
229
+ report.sessionStats = sessstats;
230
+
231
+ report.timestamp = new absl::Duration();
232
+ report.timestamp[0] = absl::Now() - absl::UnixEpoch();
233
+ if (progress_)
234
+ progress_->Send(&report, 1);
235
+ }
236
+
237
+ void Http3EventLoop::informDatagramStats(Http3WTSession *sessionobj, webtransport::DatagramStats * datastats)
238
+ {
239
+ Http3ProgressReport report;
240
+ report.type = Http3ProgressReport::DatagramStats;
241
+ report.sessionobj = sessionobj;
242
+ report.datagramStats = datastats;
243
+ report.timestamp = new absl::Duration();
244
+ report.timestamp[0] = absl::Now() - absl::UnixEpoch();
245
+ if (progress_)
246
+ progress_->Send(&report, 1);
247
+ }
248
+
223
249
  void Http3EventLoop::informUnref(LifetimeHelper *obj)
224
250
  {
225
251
  Http3ProgressReport report;
@@ -591,6 +617,70 @@ namespace quic
591
617
  cbsession_.Call({retObj});
592
618
  }
593
619
 
620
+ void Http3EventLoop::processSessionStats(Http3WTSession *sessionobj, absl::Duration* timestamp, webtransport::SessionStats * sessstats)
621
+ {
622
+ if (!checkQw())
623
+ return;
624
+ HandleScope scope(qw_->Env());
625
+
626
+
627
+ auto session = sessionobj->getJS();
628
+ if (!session)
629
+ return;
630
+ Napi::Object objVal = session->Value();
631
+
632
+ Napi::Object retObj = Napi::Object::New(qw_->Env());
633
+ retObj.Set("purpose", "SessionStats");
634
+ retObj.Set("object", objVal);
635
+ // expiredOutgoing: bigint
636
+ // lostOutgoing: bigint
637
+
638
+ // non Datagram
639
+ // minRtt: number
640
+ // smoothedRtt: number
641
+ // rttVariation: number
642
+ // estimatedSendRateBps: bigint
643
+ retObj.Set("timestamp", absl::ToDoubleMilliseconds(*timestamp)); // absl::Duration
644
+ // datagram
645
+ retObj.Set("expiredOutgoing", Napi::BigInt::New(qw_->Env(), sessstats->datagram_stats.expired_outgoing)); //uint64_t
646
+ retObj.Set("lostOutgoing", Napi::BigInt::New(qw_->Env(), sessstats->datagram_stats.lost_outgoing)); //uint64_t
647
+
648
+ // non Datagram
649
+ retObj.Set("minRtt", absl::ToDoubleMilliseconds(sessstats->min_rtt)); // absl::Duration
650
+ retObj.Set("smoothedRtt", absl::ToDoubleMilliseconds(sessstats->smoothed_rtt)); // absl::Duration
651
+ retObj.Set("rttVariation", absl::ToDoubleMilliseconds(sessstats->rtt_variation)); // absl::Duration
652
+ retObj.Set("estimatedSendRateBps", sessstats->estimated_send_rate_bps); // absl::Duration
653
+
654
+ cbsession_.Call({retObj});
655
+ delete sessstats;
656
+ delete timestamp;
657
+ }
658
+
659
+ void Http3EventLoop::processDatagramStats(Http3WTSession *sessionobj, absl::Duration* timestamp, webtransport::DatagramStats * datastats)
660
+ {
661
+ if (!checkQw())
662
+ return;
663
+ HandleScope scope(qw_->Env());
664
+
665
+
666
+ auto session = sessionobj->getJS();
667
+ if (!session)
668
+ return;
669
+ Napi::Object objVal = session->Value();
670
+
671
+ Napi::Object retObj = Napi::Object::New(qw_->Env());
672
+ retObj.Set("purpose", "DatagramStats");
673
+ retObj.Set("object", objVal);
674
+ retObj.Set("timestamp", absl::ToDoubleMilliseconds(*timestamp)); // absl::Duration
675
+ // datagram
676
+ retObj.Set("expiredOutgoing", Napi::BigInt::New(qw_->Env(), datastats->expired_outgoing)); //uint64_t
677
+ retObj.Set("lostOutgoing", Napi::BigInt::New(qw_->Env(), datastats->lost_outgoing)); //uint64_t
678
+
679
+ cbsession_.Call({retObj});
680
+ delete datastats;
681
+ delete timestamp;
682
+ }
683
+
594
684
  void Http3EventLoop::processNewSessionRequest(Http3Server *serverobj, WebTransportSession *session, spdy::Http2HeaderBlock *reqheadcopy, WebTransportRespPromisePtr *promise)
595
685
  {
596
686
  if (!checkQw())
@@ -883,6 +973,18 @@ namespace quic
883
973
  processGoawayReceived(cur.sessionobj);
884
974
  }
885
975
  break;
976
+ case Http3ProgressReport::SessionStats:
977
+ {
978
+ processSessionStats(cur.sessionobj, cur.timestamp, cur.sessionStats);
979
+ cur.para = nullptr; // take ownership of the data
980
+ }
981
+ break;
982
+ case Http3ProgressReport::DatagramStats:
983
+ {
984
+ processDatagramStats(cur.sessionobj, cur.timestamp, cur.datagramStats);
985
+ cur.para = nullptr; // take ownership of the data
986
+ }
987
+ break;
886
988
  case Http3ProgressReport::Unref:
887
989
  {
888
990
  cur.obj->doUnref();
@@ -969,8 +1071,10 @@ namespace quic
969
1071
  for (auto cur= quiche_cmd_line.begin(); cur != quiche_cmd_line.end(); cur++) {
970
1072
  quiche_cmd_line_char.push_back((*cur).c_str());
971
1073
  }
972
-
973
- quiche::QuicheParseCommandLineFlags("No use instruction.", quiche_cmd_line.size(), &(*quiche_cmd_line_char.begin()));
1074
+ if (!hasSetLogging) {
1075
+ quiche::QuicheParseCommandLineFlags("No use instruction.", quiche_cmd_line.size(), &(*quiche_cmd_line_char.begin()));
1076
+ hasSetLogging = true;
1077
+ }
974
1078
  }
975
1079
 
976
1080
  void Http3EventLoop::startEventLoop(const Napi::CallbackInfo &info)
@@ -94,6 +94,8 @@ namespace quic
94
94
  DatagramReceived,
95
95
  DatagramSend,
96
96
  GoawayReceived,
97
+ SessionStats,
98
+ DatagramStats,
97
99
  Unref
98
100
  } type;
99
101
  union
@@ -125,12 +127,15 @@ namespace quic
125
127
  {
126
128
  std::string *para = nullptr; // for session and others, we own it, and must delete it
127
129
  ServerStatusDetails *details;
130
+ webtransport::SessionStats * sessionStats; // we own it and must delete it after return from js
131
+ webtransport::DatagramStats * datagramStats; // we own it and must delete it after return from js
128
132
  };
129
133
  union
130
134
  {
131
135
  bool success;
132
136
  WebTransportRespPromisePtr *promise;
133
137
  Napi::Reference<Napi::Value> *header;
138
+ absl::Duration *timestamp; // for session and others, we own it, and must delete it
134
139
  };
135
140
  };
136
141
 
@@ -219,6 +224,9 @@ namespace quic
219
224
  void informDatagramReceived(Http3WTSession *sessionobj, absl::string_view datagram);
220
225
  void informDatagramSend(Http3WTSession *sessionobj, Napi::ObjectReference *bufferhandle);
221
226
 
227
+ void informSessionStats(Http3WTSession *sessionobj, webtransport::SessionStats * sessstats);
228
+ void informDatagramStats(Http3WTSession *sessionobj, webtransport::DatagramStats * datastats);
229
+
222
230
  void informGoawayReceived(Http3WTSession *sessionobj);
223
231
 
224
232
  void informUnref(LifetimeHelper *obj);
@@ -256,6 +264,8 @@ namespace quic
256
264
  return my_constructor;
257
265
  }
258
266
 
267
+ static bool hasSetLogging;
268
+
259
269
  void ExecuteScheduledActions();
260
270
 
261
271
  QuicMutex scheduled_actions_lock_;
@@ -286,6 +296,9 @@ namespace quic
286
296
  void processDatagramReceived(Http3WTSession *sessionobj, std::string *datagram);
287
297
  void processDatagramSend(Http3WTSession *sessionobj, Napi::ObjectReference *bufferhandle);
288
298
 
299
+ void processSessionStats(Http3WTSession *sessionobj, absl::Duration* timestamp, webtransport::SessionStats * sessstats);
300
+ void processDatagramStats(Http3WTSession *sessionobj, absl::Duration* timestamp, webtransport::DatagramStats * datastats);
301
+
289
302
  void processGoawayReceived(Http3WTSession *sessionobj);
290
303
 
291
304
  bool shutDownEventLoopInt();
@@ -10,6 +10,7 @@ namespace quic
10
10
 
11
11
  Http3WTSession::Visitor::~Visitor()
12
12
  {
13
+ // printf("~Visitor %d %x %x\n", getpid(), this, session_);
13
14
  Http3WTSessionJS *sessobj = session_->getJS();
14
15
  if (sessobj)
15
16
  session_->eventloop_->informUnref(sessobj);
@@ -21,6 +22,7 @@ namespace quic
21
22
  void Http3WTSession::Visitor::OnSessionClosed(WebTransportSessionError error_code,
22
23
  const std::string &error_message)
23
24
  {
25
+ // printf("OnSessionClosed %d %x %x\n", getpid(), this, session_);
24
26
  session_->session_ = nullptr;
25
27
  session_->eventloop_->informSessionClosed(session_, error_code, error_message);
26
28
  }
@@ -118,6 +118,7 @@ namespace quic
118
118
 
119
119
  void OnDatagramReceived(absl::string_view datagram) override
120
120
  {
121
+ // printf("OnDatagramReceived %d %x %x\n", getpid(), this, session_);
121
122
  session_->eventloop_->informDatagramReceived(session_, datagram);
122
123
  /*auto buffer = MakeUniqueBuffer(&allocator_, datagram.size());
123
124
  memcpy(buffer.get(), datagram.data(), datagram.size());
@@ -230,6 +231,28 @@ namespace quic
230
231
  eventloop_->Schedule(task);
231
232
  }
232
233
 
234
+ void orderSessionStatsInt()
235
+ {
236
+ std::function<void()> task = [this](){
237
+ if (session_) {
238
+ webtransport::SessionStats * stats = new webtransport::SessionStats();
239
+ *stats = session_->GetSessionStats();
240
+ eventloop_->informSessionStats(this, stats);
241
+ }};
242
+ eventloop_->Schedule(task);
243
+ }
244
+
245
+ void orderDatagramStatsInt()
246
+ {
247
+ std::function<void()> task = [this]()
248
+ { if (session_) {
249
+ webtransport::DatagramStats * stats = new webtransport::DatagramStats();
250
+ *stats = session_->GetDatagramStats();
251
+ eventloop_->informDatagramStats(this, stats);
252
+ } };
253
+ eventloop_->Schedule(task);
254
+ }
255
+
233
256
  void closeInt(int code, std::string &reason)
234
257
  {
235
258
  std::function<void()> task = [this, code, reason]()
@@ -239,12 +262,15 @@ namespace quic
239
262
 
240
263
  void writeDatagramInt(char *buffer, size_t len, Napi::ObjectReference *bufferhandle)
241
264
  {
265
+ // printf("Datagram write %d %x %x\n", getpid(), this, session_ );
242
266
  if (!session_)
243
267
  {
268
+ // printf("Datagram session gone %d %x %x\n", getpid(), this, session_);
244
269
  eventloop_->informDatagramSend(this, bufferhandle);
245
270
  return;
246
271
  }
247
- session_->SendOrQueueDatagram(absl::string_view(buffer, len));
272
+ auto status=session_->SendOrQueueDatagram(absl::string_view(buffer, len));
273
+ // printf("Datagram status %d %d %s %x %x\n", getpid(), status.code, status.error_message.c_str(), this, session_);
248
274
  eventloop_->informDatagramSend(this, bufferhandle);
249
275
  }
250
276
 
@@ -300,6 +326,16 @@ namespace quic
300
326
  wtsession_->notifySessionDrainingInt();
301
327
  }
302
328
 
329
+ void orderSessionStats(const Napi::CallbackInfo &info)
330
+ {
331
+ wtsession_->orderSessionStatsInt();
332
+ }
333
+
334
+ void orderDatagramStats(const Napi::CallbackInfo &info)
335
+ {
336
+ wtsession_->orderDatagramStatsInt();
337
+ }
338
+
303
339
  void close(const Napi::CallbackInfo &info)
304
340
  {
305
341
  int code = 0;
@@ -338,6 +374,10 @@ namespace quic
338
374
  static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
339
375
  InstanceMethod<&Http3WTSessionJS::notifySessionDraining>("notifySessionDraining",
340
376
  static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
377
+ InstanceMethod<&Http3WTSessionJS::orderSessionStats>("orderSessionStats",
378
+ static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
379
+ InstanceMethod<&Http3WTSessionJS::orderDatagramStats>("orderDatagramStats",
380
+ static_cast<napi_property_attributes>(napi_writable | napi_configurable)),
341
381
  InstanceMethod<&Http3WTSessionJS::close>("close",
342
382
  static_cast<napi_property_attributes>(napi_writable | napi_configurable))});
343
383
  constr->session = Napi::Persistent(tplwt);