@fails-components/webtransport 0.0.9 → 0.1.0-macarmbuild.5

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.
package/package.json CHANGED
@@ -1,21 +1,24 @@
1
1
  {
2
2
  "name": "@fails-components/webtransport",
3
- "version": "0.0.9",
3
+ "version": "0.1.0-macarmbuild.5",
4
4
  "description": "A component to add webtransport support (server and client) to node.js using libquiche",
5
- "main": "src/webtransport.js",
6
- "module": "src/webtransport.js",
5
+ "main": "lib/index.js",
6
+ "module": "lib/index.js",
7
7
  "engines": {
8
8
  "node": ">=16"
9
9
  },
10
10
  "type": "module",
11
+ "types": "./dist/lib/index.d.ts",
11
12
  "scripts": {
12
13
  "start": "node test/echoserver.js",
13
- "test": "node test/test.js",
14
+ "test": "mocha test/*.spec.js",
15
+ "oldtest": "node test/test.js",
14
16
  "install": "node build.js install",
15
17
  "build": "node build.js build",
16
18
  "rebuild": "node build.js rebuild",
17
19
  "rebuild-debug": "node build.js rebuild-debug -D",
18
- "build-debug": "node build.js build-debug"
20
+ "build-debug": "node build.js build-debug",
21
+ "types": "tsc"
19
22
  },
20
23
  "repository": {
21
24
  "type": "git",
@@ -38,6 +41,10 @@
38
41
  "devDependencies": {
39
42
  "@babel/core": "^7.17.10",
40
43
  "@babel/eslint-parser": "^7.17.0",
44
+ "@types/chai": "^4.3.3",
45
+ "@types/mocha": "^10.0.0",
46
+ "@types/node": "^18.11.5",
47
+ "chai": "^4.3.6",
41
48
  "cmake-js": "^6.3.2",
42
49
  "eslint": "^7.32.0",
43
50
  "eslint-config-prettier": "^7.2.0",
@@ -47,8 +54,10 @@
47
54
  "eslint-plugin-prettier": "^3.4.1",
48
55
  "eslint-plugin-promise": "^4.3.1",
49
56
  "eslint-plugin-standard": "^4.1.0",
57
+ "mocha": "^10.1.0",
50
58
  "node-forge": "^1.3.1",
51
- "prettier": "^2.4.1"
59
+ "prettier": "^2.4.1",
60
+ "typescript": "^4.8.4"
52
61
  },
53
62
  "binary": {
54
63
  "napi_versions": [
package/readme.md CHANGED
@@ -40,23 +40,46 @@ In case of github packages, please add to your `.npmrc` file
40
40
  ```
41
41
  In this case you need to be authenticated against github.
42
42
 
43
- The package provides prebuild binaries for `windows`, `linux` and `macos` for the platform `x64` and `ia32` (only windows).
43
+ The package provides prebuild binaries for `windows`, `linux` and `macos` for the platform `x64` and `ia32` (only windows).
44
44
  Other platforms may be possible via crosscompiling in the github actions, if someone needs this, PRs are welcome.
45
45
 
46
46
  Of course you can also build the binary on your system.
47
47
  If you are running the compiling install as root, you need to use `--unsafe-perm` as flag.
48
- Installing the package without prebuild requires a full building environment including clang-9, perl6, python, golang, ninja-build, icu. See the `Dockerfile` or `Dockerfile.development` for required debian packages.
49
- This should work for Windows, linux and Mac OS X.
48
+ Installing the package without prebuild requires a full building environment including clang-9, perl6, python, golang, ninja-build, icu. See the `Dockerfile` or `Dockerfile.development` for required debian packages.
49
+ This should work for Windows, linux and Mac OS X.
50
50
  (You may want to check out the building dependencies (especially for windows) for BoringSSl, zlib, abseil on their respective websites).
51
51
 
52
- Of course, PR for patches and for compiling instructions and necessary changes are welcome for all possible environments.
52
+ Of course, PR for patches and for compiling instructions and necessary changes are welcome for all possible environments.
53
53
 
54
54
  ** Warning the build time takes more than 15 minutes, on windows even longer! (Due to the building of the third party libraries). **
55
55
 
56
- In the directory `test` you find a simple echo server code. That answers to a series of WebTransport echos. Furthermore some example browser code and finally a unit test of the library including certificate generation.
56
+ In the directory `test` you find a simple echo server code. That answers to a series of WebTransport echos. Furthermore some example browser code and finally a unit test of the library including certificate generation.
57
57
 
58
58
  When testing remember you might need to start chromium based browser with certain flags to accept your http/3 certificate with errors, e.g.:
59
59
  ```
60
60
  chrome --ignore-certificate-errors-spki-list=FINGERPRINTOFYOURCERTIFICATE --ignore-certificate-errors --v=2 --enable-logging=stderr --origin-to-force-quic-on=192.168.1.50:8080
61
61
  ```
62
62
  of course replace IP and fingerprint of your certificate accordingly.
63
+
64
+ ## Specification divergence
65
+
66
+ This module implements parts of the [WebTransport spec](https://datatracker.ietf.org/doc/html/draft-vvv-webtransport-quic-00) but not all of it.
67
+
68
+ The types from the [W3C Working Draft](https://www.w3.org/TR/webtransport/) have been added to [lib/dom.ts](https://github.com/fails-components/webtransport/blob/master/lib/dom.ts) but some fields are commented out.
69
+
70
+ These fields are unimplemented by this module at this time. Some may be implemented in the future, others are legacy fields that may be removed from the spec. PRs are welcome!
71
+
72
+ They are:
73
+
74
+ ### WebTransport
75
+
76
+ * [getStats()](https://www.w3.org/TR/webtransport/#dom-webtransport-getstats)
77
+ * [reliability](https://www.w3.org/TR/webtransport/#dom-webtransport-reliability)
78
+
79
+ ### WebTransportDatagramDuplexStream
80
+
81
+ * [maxDatagramSize](https://www.w3.org/TR/webtransport/#dom-webtransportdatagramduplexstream-maxdatagramsize)
82
+ * [incomingMaxAge](https://www.w3.org/TR/webtransport/#dom-webtransportdatagramduplexstream-incomingmaxage)
83
+ * [outgoingMaxAge](https://www.w3.org/TR/webtransport/#dom-webtransportdatagramduplexstream-outgoingmaxage)
84
+ * [incomingHighWaterMark](https://www.w3.org/TR/webtransport/#dom-webtransportdatagramduplexstream-incominghighwatermark)
85
+ * [outgoingHighWaterMark](https://www.w3.org/TR/webtransport/#dom-webtransportdatagramduplexstream-outgoinghighwatermark)
package/src/http3client.h CHANGED
@@ -11,7 +11,6 @@
11
11
  #define WT_HTTP3_CLIENT_H
12
12
 
13
13
  #include <napi.h>
14
- #include <uv.h>
15
14
 
16
15
  #include <cstdint>
17
16
  #include <memory>
@@ -295,6 +295,17 @@ namespace quic
295
295
  progress_->Send(&report, 1);
296
296
  }
297
297
 
298
+ void Http3EventLoop::informServerStatus(Http3Server *serverobj, NetworkStatus status, ServerStatusDetails* details)
299
+ {
300
+ struct Http3ProgressReport report;
301
+ report.type = Http3ProgressReport::ServerStatus;
302
+ report.serverobj = serverobj;
303
+ report.status = status;
304
+ report.details = details;
305
+ if (progress_)
306
+ progress_->Send(&report, 1);
307
+ }
308
+
298
309
  void Http3EventLoop::freeData(Napi::Env env, void *data, std::string *hint)
299
310
  {
300
311
  // ok free data is actually using a string object
@@ -631,6 +642,41 @@ namespace quic
631
642
  cbsession_.Call({retObj});
632
643
  }
633
644
 
645
+ void Http3EventLoop::processServerStatus(Http3Server *serverobj, NetworkStatus status, ServerStatusDetails * details)
646
+ {
647
+ if (!checkQw()) return;
648
+ HandleScope scope(qw_->Env());
649
+
650
+ Napi::Object objVal = serverobj->getJS()->Value();
651
+
652
+ Napi::Object retObj = Napi::Object::New(qw_->Env());
653
+ retObj.Set("purpose", "ServerStatus");
654
+ retObj.Set("object", objVal);
655
+ Napi::Number portVal = Napi::Number::New(qw_->Env(), details->port);
656
+ retObj.Set("port", portVal);
657
+ Napi::String hostVal = Napi::String::New(qw_->Env(), details->host);
658
+ retObj.Set("host", hostVal);
659
+
660
+ delete details; // we own it and must throw it away
661
+ switch (status)
662
+ {
663
+ case NetError: {
664
+ retObj.Set("status", "error");
665
+ } break;
666
+ case NetListening: {
667
+ retObj.Set("status", "listening");
668
+ } break;
669
+ case NetClose: {
670
+ retObj.Set("status", "close");
671
+ } break;
672
+ default: {
673
+ Napi::Error::New(Env(), "Unknown status from server").ThrowAsJavaScriptException();
674
+ return;
675
+ } break;
676
+ };
677
+ cbtransport_.Call({retObj});
678
+ }
679
+
634
680
  void Http3EventLoop::HandleProgressCallback(const Http3ProgressReport *data, size_t count)
635
681
  {
636
682
  for (int i = 0; i < count; i++)
@@ -688,6 +734,12 @@ namespace quic
688
734
  processStream(false, false, cur.sessionobj, cur.stream);
689
735
  }
690
736
  break;
737
+ case Http3ProgressReport::ServerStatus:
738
+ {
739
+ processServerStatus(cur.serverobj, cur.status, cur.details);
740
+ cur.para = nullptr; // take ownership of the data
741
+ }
742
+ break;
691
743
  case Http3ProgressReport::StreamRecvSignal:
692
744
  {
693
745
  processStreamRecvSignal(cur.streamobj, cur.wtscode, cur.nettask);
@@ -47,6 +47,13 @@ namespace quic
47
47
  streamFinal
48
48
  };
49
49
 
50
+ enum NetworkStatus
51
+ {
52
+ NetError,
53
+ NetClose,
54
+ NetListening
55
+ };
56
+
50
57
  struct Http3Constructors
51
58
  {
52
59
  Napi::FunctionReference stream;
@@ -54,6 +61,11 @@ namespace quic
54
61
 
55
62
  };
56
63
 
64
+ struct ServerStatusDetails {
65
+ std::string host;
66
+ int port;
67
+ };
68
+
57
69
  class Http3ProgressReport // actually struct would be a better fit but make napi happy
58
70
  {
59
71
  public:
@@ -69,6 +81,7 @@ namespace quic
69
81
  IncomUniDiStream,
70
82
  OutgoBiDiStream,
71
83
  OutgoUniDiStream,
84
+ ServerStatus,
72
85
  StreamRecvSignal,
73
86
  StreamRead,
74
87
  StreamWrite,
@@ -91,6 +104,7 @@ namespace quic
91
104
  {
92
105
  WebTransportSessionError wtecode;
93
106
  NetworkTask nettask;
107
+ NetworkStatus status;
94
108
  };
95
109
  union
96
110
  {
@@ -104,8 +118,11 @@ namespace quic
104
118
  {
105
119
  bool success;
106
120
  };
121
+ union {
107
122
 
108
- std::string *para = nullptr; // for session, we own it, and must delete it
123
+ std::string *para = nullptr; // for session and others, we own it, and must delete it
124
+ ServerStatusDetails * details;
125
+ };
109
126
  };
110
127
 
111
128
  class Http3EventLoop : // may be replace char later
@@ -179,6 +196,8 @@ namespace quic
179
196
  void informSessionClosed(Http3WTSession *sessionobj, WebTransportSessionError error_code, absl::string_view error_message);
180
197
  void informSessionReady(Http3WTSession *sessionobj);
181
198
 
199
+ void informServerStatus(Http3Server *serverobj, NetworkStatus status, ServerStatusDetails* details);
200
+
182
201
  void informAboutStream(bool incom, bool bidir, Http3WTSession *sessionobj, Http3WTStream *stream);
183
202
  void informStreamRecvSignal(Http3WTStream *streamobj, WebTransportStreamError error_code, NetworkTask task);
184
203
  void informAboutStreamRead(Http3WTStream *streamobj, std::string *data, bool fin);
@@ -239,6 +258,8 @@ namespace quic
239
258
  void processSessionClose(Http3WTSession *sessionobj, uint32_t errorcode, const std::string &path);
240
259
  void processSessionReady(Http3WTSession *sessionobj);
241
260
 
261
+ void processServerStatus(Http3Server *serverobj, NetworkStatus status, ServerStatusDetails * details);
262
+
242
263
  void processStream(bool incom, bool bidi, Http3WTSession *sessionobj, Http3WTStream *stream);
243
264
  void processStreamRecvSignal(Http3WTStream *streamobj, WebTransportStreamError error_code, NetworkTask task);
244
265
  void processStreamRead(Http3WTStream *streamobj, std::string *data, bool fin);
@@ -93,9 +93,12 @@ namespace quic
93
93
  dispatcher_.reset(CreateQuicDispatcher());
94
94
  dispatcher_->InitializeWithWriter(new QuicDefaultPacketWriter(fd_));
95
95
  std::move(closer).Cancel();
96
+
97
+ eventloop_->informServerStatus(this, NetListening, getStatusDetails());
96
98
  return true;
97
99
  }
98
100
 
101
+ eventloop_->informServerStatus(this, NetError, getStatusDetails());
99
102
  return false;
100
103
  }
101
104
 
@@ -113,6 +116,7 @@ namespace quic
113
116
  QuicUdpSocketApi api;
114
117
  api.Destroy(fd_);
115
118
  fd_ = -1;
119
+ eventloop_->informServerStatus(this, NetClose, getStatusDetails());
116
120
  eventloop_->informUnref(this->getJS()); // must be done on the other thread...
117
121
  return true;
118
122
  }
@@ -397,5 +401,4 @@ namespace quic
397
401
  obj->eventloop_->Schedule(task);
398
402
  }
399
403
  }
400
-
401
404
  }
package/src/http3server.h CHANGED
@@ -50,6 +50,7 @@ namespace quic
50
50
 
51
51
  void addPath(const Napi::CallbackInfo &info);
52
52
 
53
+
53
54
  static void InitExports(Napi::Env env, Napi::Object exports)
54
55
  {
55
56
  Napi::Function tplsrv = DefineClass(env, "Http3WebTransportServer",
@@ -94,6 +95,13 @@ namespace quic
94
95
 
95
96
  Http3ServerJS *getJS() { return js_; };
96
97
 
98
+ ServerStatusDetails *getStatusDetails() {
99
+ ServerStatusDetails* details = new ServerStatusDetails();
100
+ details->host = host_;
101
+ details->port = port_;
102
+ return details;
103
+ }
104
+
97
105
  private:
98
106
  bool startServerInt();
99
107
  bool stopServerInt();
@@ -107,7 +107,7 @@ namespace quic
107
107
  {
108
108
  if (ShouldNegotiateWebTransport())
109
109
  {
110
- return HttpDatagramSupport::kDraft04And09;
110
+ return HttpDatagramSupport::kRfcAndDraft04;
111
111
  }
112
112
  return QuicServerSessionBase::LocalHttpDatagramSupport();
113
113
  }
@@ -0,0 +1,137 @@
1
+ /* eslint-disable no-undef */
2
+ import { createServer } from './fixtures/server.js'
3
+ import { getReaderValue } from './fixtures/reader-value.js'
4
+ import { WebTransport } from '../lib/index.js'
5
+ import { expect } from 'chai'
6
+ import { readStream } from './fixtures/read-stream.js'
7
+ import { writeStream } from './fixtures/write-stream.js'
8
+ import { defer } from '../lib/utils.js'
9
+
10
+ /**
11
+ * @template T
12
+ * @typedef {import('../lib/types').Deferred<T>} Deferred<T>
13
+ */
14
+
15
+ const SERVER_PATH = '/bidirectional-streams'
16
+
17
+ describe('bidirectional streams', function () {
18
+ /** @type {import('../lib/server').Http3Server} */
19
+ let server
20
+ /** @type {import('./fixtures/certificate.js').Certificate} */
21
+ let certificate
22
+ /** @type {import('../lib/dom').WebTransport | undefined} */
23
+ let client
24
+ /** @type {string} */
25
+ let url
26
+
27
+ this.timeout(30000) // this can vary depending on the setup and is not an error
28
+ // but it smells like a work around regarding a deeper problem
29
+
30
+ beforeEach(async () => {
31
+ this.timeout(2000)
32
+ ;({ server, certificate } = await createServer())
33
+ server.startServer()
34
+ await server.ready
35
+
36
+ const address = server.address()
37
+
38
+ if (address == null || address.port == null) {
39
+ throw new Error('No address')
40
+ }
41
+
42
+ url = `https://${address.host}:${address.port}`
43
+ })
44
+
45
+ afterEach(async () => {
46
+ if (client != null) {
47
+ client.close()
48
+ }
49
+
50
+ if (server != null) {
51
+ server.stopServer()
52
+ await server.closed
53
+ }
54
+ })
55
+
56
+ it('sends and receives data over an outgoing bidirectional stream', async () => {
57
+ this.timeout(200)
58
+ // server context - waits for the client to open a bidi stream and pipes it back to them
59
+ Promise.resolve().then(async () => {
60
+ const session = await getReaderValue(server.sessionStream(SERVER_PATH))
61
+ const bidiStream = await getReaderValue(
62
+ session.incomingBidirectionalStreams
63
+ )
64
+ // redirect input to output
65
+ await bidiStream.readable.pipeTo(bidiStream.writable)
66
+ })
67
+
68
+ // client context - connects to the server, opens a bidi stream, sends some data and reads the response
69
+ client = new WebTransport(`${url}${SERVER_PATH}`, {
70
+ serverCertificateHashes: [
71
+ {
72
+ algorithm: 'sha-256',
73
+ value: certificate.hash
74
+ }
75
+ ]
76
+ })
77
+ await client.ready
78
+
79
+ const input = [
80
+ Uint8Array.from([0, 1, 2, 3, 4]),
81
+ Uint8Array.from([5, 6, 7, 8, 9]),
82
+ Uint8Array.from([10, 11, 12, 13, 14])
83
+ ]
84
+
85
+ const stream = await client.createBidirectionalStream()
86
+ await writeStream(stream.writable, input)
87
+
88
+ const output = await readStream(stream.readable)
89
+ expect(output).to.deep.equal(
90
+ input,
91
+ 'Did not receive the same bytes we sent'
92
+ )
93
+ })
94
+
95
+ it('sends and receives data over an incoming bidirectional stream', async () => {
96
+ this.timeout(200)
97
+ /** @type {Deferred<Uint8Array[]>} */
98
+ const serverData = defer()
99
+ const input = [
100
+ Uint8Array.from([0, 1, 2, 3, 4]),
101
+ Uint8Array.from([5, 6, 7, 8, 9]),
102
+ Uint8Array.from([10, 11, 12, 13, 14])
103
+ ]
104
+
105
+ // server context - waits for the client to connect, opens a bidi stream, sends some data and reads the response
106
+ Promise.resolve().then(async () => {
107
+ const session = await getReaderValue(server.sessionStream(SERVER_PATH))
108
+ const stream = await session.createBidirectionalStream()
109
+
110
+ await writeStream(stream.writable, input)
111
+
112
+ const output = await readStream(stream.readable)
113
+ serverData.resolve(output)
114
+ })
115
+
116
+ // client context - waits for the server to open a bidi stream then pipes it back to them
117
+ client = new WebTransport(`${url}${SERVER_PATH}`, {
118
+ serverCertificateHashes: [
119
+ {
120
+ algorithm: 'sha-256',
121
+ value: certificate.hash
122
+ }
123
+ ]
124
+ })
125
+ await client.ready
126
+
127
+ const bidiStream = await getReaderValue(client.incomingBidirectionalStreams)
128
+ // redirect input to output
129
+ await bidiStream.readable.pipeTo(bidiStream.writable)
130
+
131
+ const received = await serverData.promise
132
+ expect(received).to.deep.equal(
133
+ input,
134
+ 'Did not receive the same bytes we sent'
135
+ )
136
+ })
137
+ })
@@ -0,0 +1,131 @@
1
+ /* eslint-disable no-undef */
2
+ import { createServer } from './fixtures/server.js'
3
+ import { getReaderValue } from './fixtures/reader-value.js'
4
+ import { WebTransport } from '../lib/index.js'
5
+ import { expect } from 'chai'
6
+ import { readStream } from './fixtures/read-stream.js'
7
+ import { writeStream } from './fixtures/write-stream.js'
8
+ import { defer } from '../lib/utils.js'
9
+
10
+ /**
11
+ * @template T
12
+ * @typedef {import('../lib/types').Deferred<T>} Deferred<T>
13
+ */
14
+
15
+ const SERVER_PATH = '/datagrams'
16
+
17
+ describe('datagrams', function () {
18
+ /** @type {import('../lib/server').Http3Server} */
19
+ let server
20
+ /** @type {import('./fixtures/certificate.js').Certificate} */
21
+ let certificate
22
+ /** @type {import('../lib/dom').WebTransport | undefined} */
23
+ let client
24
+ /** @type {string} */
25
+ let url
26
+
27
+ beforeEach(async () => {
28
+ ;({ server, certificate } = await createServer())
29
+ server.startServer()
30
+ await server.ready
31
+
32
+ const address = server.address()
33
+
34
+ if (address == null || address.port == null) {
35
+ throw new Error('No address')
36
+ }
37
+
38
+ url = `https://${address.host}:${address.port}`
39
+ })
40
+
41
+ afterEach(async () => {
42
+ if (client != null) {
43
+ client.close()
44
+ }
45
+
46
+ if (server != null) {
47
+ server.stopServer()
48
+ await server.closed
49
+ }
50
+ })
51
+
52
+ it('client sends datagrams to the server', async () => {
53
+ this.timeout(200)
54
+ // server context - waits for the client to connect and pipes their datagrams back to them
55
+ Promise.resolve().then(async () => {
56
+ const session = await getReaderValue(server.sessionStream(SERVER_PATH))
57
+
58
+ // redirect input to output
59
+ await session.datagrams.readable.pipeTo(session.datagrams.writable)
60
+ })
61
+
62
+ // client context - connects to the server, sends some datagrams and reads the response
63
+ client = new WebTransport(`${url}${SERVER_PATH}`, {
64
+ serverCertificateHashes: [
65
+ {
66
+ algorithm: 'sha-256',
67
+ value: certificate.hash
68
+ }
69
+ ]
70
+ })
71
+ await client.ready
72
+
73
+ const input = [
74
+ Uint8Array.from([0, 1, 2, 3, 4]),
75
+ Uint8Array.from([5, 6, 7, 8, 9]),
76
+ Uint8Array.from([10, 11, 12, 13, 14])
77
+ ]
78
+
79
+ await writeStream(client.datagrams.writable, input)
80
+
81
+ const output = await readStream(client.datagrams.readable, input.length)
82
+ expect(output).to.deep.equal(
83
+ input,
84
+ 'Did not receive the same bytes we sent'
85
+ )
86
+ })
87
+
88
+ it('receives datagrams from the server', async () => {
89
+ this.timeout(200)
90
+ /** @type {Deferred<Uint8Array[]>} */
91
+ const serverData = defer()
92
+ const input = [
93
+ Uint8Array.from([0, 1, 2, 3, 4]),
94
+ Uint8Array.from([5, 6, 7, 8, 9]),
95
+ Uint8Array.from([10, 11, 12, 13, 14])
96
+ ]
97
+
98
+ // server context - waits for the client to connect, sends some datagrams and reads the response
99
+ Promise.resolve().then(async () => {
100
+ const session = await getReaderValue(server.sessionStream(SERVER_PATH))
101
+
102
+ await writeStream(session.datagrams.writable, input)
103
+
104
+ const output = await readStream(session.datagrams.readable, input.length)
105
+
106
+ // have to close the session to end the client's datagram stream
107
+ session.close()
108
+ serverData.resolve(output)
109
+ })
110
+
111
+ // client context - pipes the server's datagrams back to them
112
+ client = new WebTransport(`${url}${SERVER_PATH}`, {
113
+ serverCertificateHashes: [
114
+ {
115
+ algorithm: 'sha-256',
116
+ value: certificate.hash
117
+ }
118
+ ]
119
+ })
120
+ await client.ready
121
+
122
+ // redirect input to output
123
+ await client.datagrams.readable.pipeTo(client.datagrams.writable)
124
+
125
+ const received = await serverData.promise
126
+ expect(received).to.deep.equal(
127
+ input,
128
+ 'Did not receive the same bytes we sent'
129
+ )
130
+ })
131
+ })
@@ -3,18 +3,22 @@
3
3
  // found in the LICENSE file.
4
4
 
5
5
  import { echoTestsConnection } from './testsuite.js'
6
- import { WebTransport } from '../src/webtransport.js'
6
+ import { WebTransport } from '../lib/index.js'
7
7
 
8
+ /**
9
+ * @param {{ hostname: string, port: number }} args
10
+ * @param {{ serverCertificateHashes: Array<{ algorithm: string, value: string }> }} hashes
11
+ */
8
12
  async function startClientTests(args, hashes) {
9
13
  const url = 'https://' + args.hostname + ':' + args.port + '/echo'
10
14
  console.log('startconnection')
11
- const hashargs = { ...hashes }
12
- hashargs.serverCertificateHashes = hashes.serverCertificateHashes.map(
13
- (el) => ({
15
+ const hashargs = {
16
+ ...hashes,
17
+ serverCertificateHashes: hashes.serverCertificateHashes.map((el) => ({
14
18
  algorithm: el.algorithm,
15
19
  value: Buffer.from(el.value.split(':').map((el) => parseInt(el, 16)))
16
- })
17
- )
20
+ }))
21
+ }
18
22
  // eslint-disable-next-line no-undef
19
23
  console.log('hashagrs', hashargs)
20
24
  const transport = new WebTransport(url, hashargs)
@@ -2,11 +2,11 @@
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
4
 
5
- import { Http3Server } from '../src/webtransport.js'
5
+ import { Http3Server } from '../lib/index.js'
6
6
  import { runEchoServer } from './testsuite.js'
7
7
  import { existsSync, readFileSync, writeFile } from 'node:fs'
8
- import { generateWebTransportCertificate } from './certificate.js'
9
-
8
+ // @ts-ignore
9
+ import { generateWebTransportCertificate } from './fixtures/certificate.js'
10
10
 
11
11
  let certificate = null
12
12
 
@@ -27,24 +27,22 @@ if (!certificate) {
27
27
  certificate = await generateWebTransportCertificate(attrs, {
28
28
  days: 13
29
29
  })
30
- writeFile('./certificatecache.json', JSON.stringify(certificate),(err)=>{
30
+ writeFile('./certificatecache.json', JSON.stringify(certificate), (err) => {
31
31
  if (err) console.log('write certificate cache error', err)
32
32
  })
33
33
  }
34
34
 
35
35
  console.log('certificate hash ', certificate.fingerprint)
36
36
 
37
-
38
-
39
37
  try {
40
38
  const http3server = new Http3Server({
41
39
  port: 8080,
42
40
  host: '0.0.0.0',
43
41
  secret: 'mysecret',
44
- cert: certificate.cert,
42
+ cert: certificate.cert,
45
43
  privKey: certificate.private
46
44
  })
47
-
45
+
48
46
  runEchoServer(http3server)
49
47
  http3server.startServer() // you can call destroy to remove the server
50
48
  } catch (error) {
@@ -0,0 +1,23 @@
1
+ /* eslint-disable no-undef */
2
+ import { expect } from 'chai'
3
+ import { Http3EventLoop } from '../lib/event-loop.js'
4
+
5
+ describe('event-loop', () => {
6
+ beforeEach(() => {
7
+ if (Http3EventLoop.globalLoop != null) {
8
+ // shut down loop, otherwise we have to wait for
9
+ // it to time out which takes a long time.
10
+ Http3EventLoop.globalLoop.shutdownEventLoop()
11
+ }
12
+ })
13
+
14
+ it('should start and stop the event loop', () => {
15
+ expect(Http3EventLoop.globalLoop).to.be.null
16
+
17
+ Http3EventLoop.createGlobalEventLoop()
18
+ expect(Http3EventLoop.globalLoop).to.not.be.null
19
+
20
+ Http3EventLoop.globalLoop?.shutdownEventLoop()
21
+ expect(Http3EventLoop.globalLoop).to.be.null
22
+ })
23
+ })