@libp2p/webtransport 3.0.11 → 3.1.0-972b10a9
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/dist/index.min.js +7 -7
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +67 -54
- package/dist/src/index.js.map +1 -1
- package/package.json +6 -5
- package/src/index.ts +83 -60
- package/dist/typedoc-urls.json +0 -8
package/dist/src/index.d.ts
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { type Transport } from '@libp2p/interface/transport';
|
|
2
|
+
import type { CounterGroup, Metrics } from '@libp2p/interface/metrics';
|
|
2
3
|
import type { PeerId } from '@libp2p/interface/peer-id';
|
|
3
4
|
export interface WebTransportInit {
|
|
4
5
|
maxInboundStreams?: number;
|
|
5
6
|
}
|
|
6
7
|
export interface WebTransportComponents {
|
|
7
8
|
peerId: PeerId;
|
|
9
|
+
metrics?: Metrics;
|
|
10
|
+
}
|
|
11
|
+
export interface WebTransportMetrics {
|
|
12
|
+
dialerEvents: CounterGroup;
|
|
8
13
|
}
|
|
9
14
|
export declare function webTransport(init?: WebTransportInit): (components: WebTransportComponents) => Transport;
|
|
10
15
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/src/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAAuE,MAAM,6BAA6B,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAAuE,MAAM,6BAA6B,CAAA;AASjI,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAA;AACtE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAA;AAWvD,MAAM,WAAW,gBAAgB;IAC/B,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,YAAY,CAAA;CAC3B;AA+SD,wBAAgB,YAAY,CAAE,IAAI,GAAE,gBAAqB,GAAG,CAAC,UAAU,EAAE,sBAAsB,KAAK,SAAS,CAE5G"}
|
package/dist/src/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import { noise } from '@chainsafe/libp2p-noise';
|
|
|
2
2
|
import { symbol } from '@libp2p/interface/transport';
|
|
3
3
|
import { logger } from '@libp2p/logger';
|
|
4
4
|
import {} from '@multiformats/multiaddr';
|
|
5
|
+
import { WebTransport as WebTransportMatcher } from '@multiformats/multiaddr-matcher';
|
|
5
6
|
import { webtransportBiDiStreamToStream } from './stream.js';
|
|
6
7
|
import { inertDuplex } from './utils/inert-duplex.js';
|
|
7
8
|
import { isSubset } from './utils/is-subset.js';
|
|
@@ -10,11 +11,20 @@ const log = logger('libp2p:webtransport');
|
|
|
10
11
|
class WebTransportTransport {
|
|
11
12
|
components;
|
|
12
13
|
config;
|
|
14
|
+
metrics;
|
|
13
15
|
constructor(components, init = {}) {
|
|
14
16
|
this.components = components;
|
|
15
17
|
this.config = {
|
|
16
18
|
maxInboundStreams: init.maxInboundStreams ?? 1000
|
|
17
19
|
};
|
|
20
|
+
if (components.metrics != null) {
|
|
21
|
+
this.metrics = {
|
|
22
|
+
dialerEvents: components.metrics.registerCounterGroup('libp2p_webtransport_dialer_events_total', {
|
|
23
|
+
label: 'event',
|
|
24
|
+
help: 'Total count of WebTransport dialer events by type'
|
|
25
|
+
})
|
|
26
|
+
};
|
|
27
|
+
}
|
|
18
28
|
}
|
|
19
29
|
[Symbol.toStringTag] = '@libp2p/webtransport';
|
|
20
30
|
[symbol] = true;
|
|
@@ -36,75 +46,74 @@ class WebTransportTransport {
|
|
|
36
46
|
let abortListener;
|
|
37
47
|
let maConn;
|
|
38
48
|
let cleanUpWTSession = () => { };
|
|
49
|
+
let closed = false;
|
|
50
|
+
let ready = false;
|
|
51
|
+
let authenticated = false;
|
|
39
52
|
try {
|
|
40
|
-
|
|
53
|
+
this.metrics?.dialerEvents.increment({ pending: true });
|
|
41
54
|
const wt = new WebTransport(`${url}/.well-known/libp2p-webtransport?type=noise`, {
|
|
42
55
|
serverCertificateHashes: certhashes.map(certhash => ({
|
|
43
56
|
algorithm: 'sha-256',
|
|
44
57
|
value: certhash.digest
|
|
45
58
|
}))
|
|
46
59
|
});
|
|
47
|
-
cleanUpWTSession = (
|
|
60
|
+
cleanUpWTSession = (metric) => {
|
|
61
|
+
if (closed) {
|
|
62
|
+
// already closed session
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
48
65
|
try {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
// already closed session
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
// This is how we specify the connection is closed and shouldn't be used.
|
|
55
|
-
maConn.timeline.close = Date.now();
|
|
56
|
-
}
|
|
57
|
-
if (closed) {
|
|
58
|
-
// already closed session
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
wt.close(closeInfo);
|
|
66
|
+
this.metrics?.dialerEvents.increment({ [metric]: true });
|
|
67
|
+
wt.close();
|
|
62
68
|
}
|
|
63
69
|
catch (err) {
|
|
64
70
|
log.error('error closing wt session', err);
|
|
65
71
|
}
|
|
66
72
|
finally {
|
|
73
|
+
// This is how we specify the connection is closed and shouldn't be used.
|
|
74
|
+
if (maConn != null) {
|
|
75
|
+
maConn.timeline.close = Date.now();
|
|
76
|
+
}
|
|
67
77
|
closed = true;
|
|
68
78
|
}
|
|
69
79
|
};
|
|
70
|
-
// this promise resolves/throws when the session is closed or failed to init
|
|
71
|
-
wt.closed
|
|
72
|
-
.then(async () => {
|
|
73
|
-
await maConn?.close();
|
|
74
|
-
})
|
|
75
|
-
.catch((err) => {
|
|
76
|
-
log.error('error on remote wt session close', err);
|
|
77
|
-
maConn?.abort(err);
|
|
78
|
-
})
|
|
79
|
-
.finally(() => {
|
|
80
|
-
// if we never got as far as creating the maConn, just clean up the session
|
|
81
|
-
if (maConn == null) {
|
|
82
|
-
cleanUpWTSession();
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
80
|
// if the dial is aborted before we are ready, close the WebTransport session
|
|
86
81
|
abortListener = () => {
|
|
87
|
-
if (
|
|
88
|
-
|
|
82
|
+
if (ready) {
|
|
83
|
+
cleanUpWTSession('noise_timeout');
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
cleanUpWTSession('ready_timeout');
|
|
89
87
|
}
|
|
90
|
-
cleanUpWTSession();
|
|
91
88
|
};
|
|
92
|
-
options.signal?.addEventListener('abort', abortListener
|
|
93
|
-
|
|
89
|
+
options.signal?.addEventListener('abort', abortListener, {
|
|
90
|
+
once: true
|
|
91
|
+
});
|
|
92
|
+
await Promise.race([
|
|
93
|
+
wt.closed,
|
|
94
|
+
wt.ready
|
|
95
|
+
]);
|
|
96
|
+
ready = true;
|
|
97
|
+
this.metrics?.dialerEvents.increment({ ready: true });
|
|
98
|
+
// this promise resolves/throws when the session is closed
|
|
99
|
+
wt.closed.catch((err) => {
|
|
100
|
+
log.error('error on remote wt session close', err);
|
|
101
|
+
})
|
|
102
|
+
.finally(() => {
|
|
103
|
+
cleanUpWTSession('remote_close');
|
|
104
|
+
});
|
|
94
105
|
if (!await this.authenticateWebTransport(wt, localPeer, remotePeer, certhashes)) {
|
|
95
106
|
throw new Error('Failed to authenticate webtransport');
|
|
96
107
|
}
|
|
108
|
+
this.metrics?.dialerEvents.increment({ open: true });
|
|
97
109
|
maConn = {
|
|
98
|
-
close: async (
|
|
110
|
+
close: async () => {
|
|
99
111
|
log('Closing webtransport');
|
|
100
|
-
cleanUpWTSession();
|
|
112
|
+
cleanUpWTSession('close');
|
|
101
113
|
},
|
|
102
114
|
abort: (err) => {
|
|
103
115
|
log('aborting webtransport due to passed err', err);
|
|
104
|
-
cleanUpWTSession(
|
|
105
|
-
closeCode: 0,
|
|
106
|
-
reason: err.message
|
|
107
|
-
});
|
|
116
|
+
cleanUpWTSession('abort');
|
|
108
117
|
},
|
|
109
118
|
remoteAddr: ma,
|
|
110
119
|
timeline: {
|
|
@@ -113,15 +122,20 @@ class WebTransportTransport {
|
|
|
113
122
|
// This connection is never used directly since webtransport supports native streams.
|
|
114
123
|
...inertDuplex()
|
|
115
124
|
};
|
|
116
|
-
|
|
117
|
-
return await options.upgrader.upgradeOutbound(maConn, { skipEncryption: true, muxerFactory: this.webtransportMuxer(wt
|
|
125
|
+
authenticated = true;
|
|
126
|
+
return await options.upgrader.upgradeOutbound(maConn, { skipEncryption: true, muxerFactory: this.webtransportMuxer(wt), skipProtection: true });
|
|
118
127
|
}
|
|
119
128
|
catch (err) {
|
|
120
129
|
log.error('caught wt session err', err);
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
130
|
+
if (authenticated) {
|
|
131
|
+
cleanUpWTSession('upgrade_error');
|
|
132
|
+
}
|
|
133
|
+
else if (ready) {
|
|
134
|
+
cleanUpWTSession('noise_error');
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
cleanUpWTSession('ready_error');
|
|
138
|
+
}
|
|
125
139
|
throw err;
|
|
126
140
|
}
|
|
127
141
|
finally {
|
|
@@ -168,7 +182,7 @@ class WebTransportTransport {
|
|
|
168
182
|
}
|
|
169
183
|
return true;
|
|
170
184
|
}
|
|
171
|
-
webtransportMuxer(wt
|
|
185
|
+
webtransportMuxer(wt) {
|
|
172
186
|
let streamIDCounter = 0;
|
|
173
187
|
const config = this.config;
|
|
174
188
|
return {
|
|
@@ -220,14 +234,13 @@ class WebTransportTransport {
|
|
|
220
234
|
*/
|
|
221
235
|
close: async (options) => {
|
|
222
236
|
log('Closing webtransport muxer');
|
|
223
|
-
|
|
237
|
+
await Promise.all(activeStreams.map(async (s) => s.close(options)));
|
|
224
238
|
},
|
|
225
239
|
abort: (err) => {
|
|
226
240
|
log('Aborting webtransport muxer with err:', err);
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
});
|
|
241
|
+
for (const stream of activeStreams) {
|
|
242
|
+
stream.abort(err);
|
|
243
|
+
}
|
|
231
244
|
},
|
|
232
245
|
// This stream muxer is webtransport native. Therefore it doesn't plug in with any other duplex.
|
|
233
246
|
...inertDuplex()
|
|
@@ -243,7 +256,7 @@ class WebTransportTransport {
|
|
|
243
256
|
* Takes a list of `Multiaddr`s and returns only valid webtransport addresses.
|
|
244
257
|
*/
|
|
245
258
|
filter(multiaddrs) {
|
|
246
|
-
return multiaddrs.filter(
|
|
259
|
+
return multiaddrs.filter(WebTransportMatcher.exactMatch);
|
|
247
260
|
}
|
|
248
261
|
}
|
|
249
262
|
export function webTransport(init = {}) {
|
package/dist/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAA;AAC/C,OAAO,EAAkB,MAAM,EAA+D,MAAM,6BAA6B,CAAA;AACjI,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AACvC,OAAO,EAAqC,MAAM,yBAAyB,CAAA;AAC3E,OAAO,EAAE,8BAA8B,EAAE,MAAM,aAAa,CAAA;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@libp2p/webtransport",
|
|
3
|
-
"version": "3.0
|
|
3
|
+
"version": "3.1.0-972b10a9",
|
|
4
4
|
"description": "JavaScript implementation of the WebTransport module that libp2p uses and that implements the interface-transport spec",
|
|
5
5
|
"license": "Apache-2.0 OR MIT",
|
|
6
6
|
"homepage": "https://github.com/libp2p/js-libp2p/tree/master/packages/transport-webtransport#readme",
|
|
@@ -61,9 +61,9 @@
|
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
63
|
"@chainsafe/libp2p-noise": "^13.0.0",
|
|
64
|
-
"@libp2p/interface": "
|
|
65
|
-
"@libp2p/logger": "
|
|
66
|
-
"@libp2p/peer-id": "
|
|
64
|
+
"@libp2p/interface": "0.1.2-972b10a9",
|
|
65
|
+
"@libp2p/logger": "3.0.2-972b10a9",
|
|
66
|
+
"@libp2p/peer-id": "3.0.2-972b10a9",
|
|
67
67
|
"@multiformats/multiaddr": "^12.1.5",
|
|
68
68
|
"@multiformats/multiaddr-matcher": "^1.0.1",
|
|
69
69
|
"it-stream-types": "^2.0.1",
|
|
@@ -72,8 +72,9 @@
|
|
|
72
72
|
"uint8arrays": "^4.0.6"
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|
|
75
|
+
"@libp2p/peer-id-factory": "3.0.4-972b10a9",
|
|
75
76
|
"aegir": "^40.0.8",
|
|
76
|
-
"libp2p": "
|
|
77
|
+
"libp2p": "0.46.11-972b10a9",
|
|
77
78
|
"p-defer": "^4.0.0"
|
|
78
79
|
},
|
|
79
80
|
"browser": {
|
package/src/index.ts
CHANGED
|
@@ -2,18 +2,20 @@ import { noise } from '@chainsafe/libp2p-noise'
|
|
|
2
2
|
import { type Transport, symbol, type CreateListenerOptions, type DialOptions, type Listener } from '@libp2p/interface/transport'
|
|
3
3
|
import { logger } from '@libp2p/logger'
|
|
4
4
|
import { type Multiaddr, type AbortOptions } from '@multiformats/multiaddr'
|
|
5
|
+
import { WebTransport as WebTransportMatcher } from '@multiformats/multiaddr-matcher'
|
|
5
6
|
import { webtransportBiDiStreamToStream } from './stream.js'
|
|
6
7
|
import { inertDuplex } from './utils/inert-duplex.js'
|
|
7
8
|
import { isSubset } from './utils/is-subset.js'
|
|
8
9
|
import { parseMultiaddr } from './utils/parse-multiaddr.js'
|
|
9
10
|
import type { Connection, MultiaddrConnection, Stream } from '@libp2p/interface/connection'
|
|
11
|
+
import type { CounterGroup, Metrics } from '@libp2p/interface/metrics'
|
|
10
12
|
import type { PeerId } from '@libp2p/interface/peer-id'
|
|
11
13
|
import type { StreamMuxerFactory, StreamMuxerInit, StreamMuxer } from '@libp2p/interface/stream-muxer'
|
|
12
14
|
import type { Source } from 'it-stream-types'
|
|
13
15
|
import type { MultihashDigest } from 'multiformats/hashes/interface'
|
|
14
16
|
|
|
15
17
|
interface WebTransportSessionCleanup {
|
|
16
|
-
(
|
|
18
|
+
(metric: string): void
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
const log = logger('libp2p:webtransport')
|
|
@@ -24,17 +26,32 @@ export interface WebTransportInit {
|
|
|
24
26
|
|
|
25
27
|
export interface WebTransportComponents {
|
|
26
28
|
peerId: PeerId
|
|
29
|
+
metrics?: Metrics
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface WebTransportMetrics {
|
|
33
|
+
dialerEvents: CounterGroup
|
|
27
34
|
}
|
|
28
35
|
|
|
29
36
|
class WebTransportTransport implements Transport {
|
|
30
37
|
private readonly components: WebTransportComponents
|
|
31
38
|
private readonly config: Required<WebTransportInit>
|
|
39
|
+
private readonly metrics?: WebTransportMetrics
|
|
32
40
|
|
|
33
41
|
constructor (components: WebTransportComponents, init: WebTransportInit = {}) {
|
|
34
42
|
this.components = components
|
|
35
43
|
this.config = {
|
|
36
44
|
maxInboundStreams: init.maxInboundStreams ?? 1000
|
|
37
45
|
}
|
|
46
|
+
|
|
47
|
+
if (components.metrics != null) {
|
|
48
|
+
this.metrics = {
|
|
49
|
+
dialerEvents: components.metrics.registerCounterGroup('libp2p_webtransport_dialer_events_total', {
|
|
50
|
+
label: 'event',
|
|
51
|
+
help: 'Total count of WebTransport dialer events by type'
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
}
|
|
38
55
|
}
|
|
39
56
|
|
|
40
57
|
readonly [Symbol.toStringTag] = '@libp2p/webtransport'
|
|
@@ -65,10 +82,15 @@ class WebTransportTransport implements Transport {
|
|
|
65
82
|
let abortListener: (() => void) | undefined
|
|
66
83
|
let maConn: MultiaddrConnection | undefined
|
|
67
84
|
|
|
68
|
-
let cleanUpWTSession:
|
|
85
|
+
let cleanUpWTSession: WebTransportSessionCleanup = () => {}
|
|
86
|
+
|
|
87
|
+
let closed = false
|
|
88
|
+
let ready = false
|
|
89
|
+
let authenticated = false
|
|
69
90
|
|
|
70
91
|
try {
|
|
71
|
-
|
|
92
|
+
this.metrics?.dialerEvents.increment({ pending: true })
|
|
93
|
+
|
|
72
94
|
const wt = new WebTransport(`${url}/.well-known/libp2p-webtransport?type=noise`, {
|
|
73
95
|
serverCertificateHashes: certhashes.map(certhash => ({
|
|
74
96
|
algorithm: 'sha-256',
|
|
@@ -76,74 +98,69 @@ class WebTransportTransport implements Transport {
|
|
|
76
98
|
}))
|
|
77
99
|
})
|
|
78
100
|
|
|
79
|
-
cleanUpWTSession = (
|
|
101
|
+
cleanUpWTSession = (metric: string) => {
|
|
102
|
+
if (closed) {
|
|
103
|
+
// already closed session
|
|
104
|
+
return
|
|
105
|
+
}
|
|
106
|
+
|
|
80
107
|
try {
|
|
108
|
+
this.metrics?.dialerEvents.increment({ [metric]: true })
|
|
109
|
+
wt.close()
|
|
110
|
+
} catch (err) {
|
|
111
|
+
log.error('error closing wt session', err)
|
|
112
|
+
} finally {
|
|
113
|
+
// This is how we specify the connection is closed and shouldn't be used.
|
|
81
114
|
if (maConn != null) {
|
|
82
|
-
if (maConn.timeline.close != null) {
|
|
83
|
-
// already closed session
|
|
84
|
-
return
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// This is how we specify the connection is closed and shouldn't be used.
|
|
88
115
|
maConn.timeline.close = Date.now()
|
|
89
116
|
}
|
|
90
117
|
|
|
91
|
-
if (closed) {
|
|
92
|
-
// already closed session
|
|
93
|
-
return
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
wt.close(closeInfo)
|
|
97
|
-
} catch (err) {
|
|
98
|
-
log.error('error closing wt session', err)
|
|
99
|
-
} finally {
|
|
100
118
|
closed = true
|
|
101
119
|
}
|
|
102
120
|
}
|
|
103
121
|
|
|
104
|
-
// this promise resolves/throws when the session is closed or failed to init
|
|
105
|
-
wt.closed
|
|
106
|
-
.then(async () => {
|
|
107
|
-
await maConn?.close()
|
|
108
|
-
})
|
|
109
|
-
.catch((err: Error) => {
|
|
110
|
-
log.error('error on remote wt session close', err)
|
|
111
|
-
maConn?.abort(err)
|
|
112
|
-
})
|
|
113
|
-
.finally(() => {
|
|
114
|
-
// if we never got as far as creating the maConn, just clean up the session
|
|
115
|
-
if (maConn == null) {
|
|
116
|
-
cleanUpWTSession()
|
|
117
|
-
}
|
|
118
|
-
})
|
|
119
|
-
|
|
120
122
|
// if the dial is aborted before we are ready, close the WebTransport session
|
|
121
123
|
abortListener = () => {
|
|
122
|
-
if (
|
|
123
|
-
|
|
124
|
+
if (ready) {
|
|
125
|
+
cleanUpWTSession('noise_timeout')
|
|
126
|
+
} else {
|
|
127
|
+
cleanUpWTSession('ready_timeout')
|
|
124
128
|
}
|
|
125
|
-
|
|
126
|
-
cleanUpWTSession()
|
|
127
129
|
}
|
|
128
|
-
options.signal?.addEventListener('abort', abortListener
|
|
130
|
+
options.signal?.addEventListener('abort', abortListener, {
|
|
131
|
+
once: true
|
|
132
|
+
})
|
|
129
133
|
|
|
130
|
-
await
|
|
134
|
+
await Promise.race([
|
|
135
|
+
wt.closed,
|
|
136
|
+
wt.ready
|
|
137
|
+
])
|
|
138
|
+
|
|
139
|
+
ready = true
|
|
140
|
+
this.metrics?.dialerEvents.increment({ ready: true })
|
|
141
|
+
|
|
142
|
+
// this promise resolves/throws when the session is closed
|
|
143
|
+
wt.closed.catch((err: Error) => {
|
|
144
|
+
log.error('error on remote wt session close', err)
|
|
145
|
+
})
|
|
146
|
+
.finally(() => {
|
|
147
|
+
cleanUpWTSession('remote_close')
|
|
148
|
+
})
|
|
131
149
|
|
|
132
150
|
if (!await this.authenticateWebTransport(wt, localPeer, remotePeer, certhashes)) {
|
|
133
151
|
throw new Error('Failed to authenticate webtransport')
|
|
134
152
|
}
|
|
135
153
|
|
|
154
|
+
this.metrics?.dialerEvents.increment({ open: true })
|
|
155
|
+
|
|
136
156
|
maConn = {
|
|
137
|
-
close: async (
|
|
157
|
+
close: async () => {
|
|
138
158
|
log('Closing webtransport')
|
|
139
|
-
cleanUpWTSession()
|
|
159
|
+
cleanUpWTSession('close')
|
|
140
160
|
},
|
|
141
161
|
abort: (err: Error) => {
|
|
142
162
|
log('aborting webtransport due to passed err', err)
|
|
143
|
-
cleanUpWTSession(
|
|
144
|
-
closeCode: 0,
|
|
145
|
-
reason: err.message
|
|
146
|
-
})
|
|
163
|
+
cleanUpWTSession('abort')
|
|
147
164
|
},
|
|
148
165
|
remoteAddr: ma,
|
|
149
166
|
timeline: {
|
|
@@ -153,16 +170,19 @@ class WebTransportTransport implements Transport {
|
|
|
153
170
|
...inertDuplex()
|
|
154
171
|
}
|
|
155
172
|
|
|
156
|
-
|
|
173
|
+
authenticated = true
|
|
157
174
|
|
|
158
|
-
return await options.upgrader.upgradeOutbound(maConn, { skipEncryption: true, muxerFactory: this.webtransportMuxer(wt
|
|
175
|
+
return await options.upgrader.upgradeOutbound(maConn, { skipEncryption: true, muxerFactory: this.webtransportMuxer(wt), skipProtection: true })
|
|
159
176
|
} catch (err: any) {
|
|
160
177
|
log.error('caught wt session err', err)
|
|
161
178
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
179
|
+
if (authenticated) {
|
|
180
|
+
cleanUpWTSession('upgrade_error')
|
|
181
|
+
} else if (ready) {
|
|
182
|
+
cleanUpWTSession('noise_error')
|
|
183
|
+
} else {
|
|
184
|
+
cleanUpWTSession('ready_error')
|
|
185
|
+
}
|
|
166
186
|
|
|
167
187
|
throw err
|
|
168
188
|
} finally {
|
|
@@ -220,7 +240,7 @@ class WebTransportTransport implements Transport {
|
|
|
220
240
|
return true
|
|
221
241
|
}
|
|
222
242
|
|
|
223
|
-
webtransportMuxer (wt: WebTransport
|
|
243
|
+
webtransportMuxer (wt: WebTransport): StreamMuxerFactory {
|
|
224
244
|
let streamIDCounter = 0
|
|
225
245
|
const config = this.config
|
|
226
246
|
return {
|
|
@@ -281,14 +301,17 @@ class WebTransportTransport implements Transport {
|
|
|
281
301
|
*/
|
|
282
302
|
close: async (options?: AbortOptions) => {
|
|
283
303
|
log('Closing webtransport muxer')
|
|
284
|
-
|
|
304
|
+
|
|
305
|
+
await Promise.all(
|
|
306
|
+
activeStreams.map(async s => s.close(options))
|
|
307
|
+
)
|
|
285
308
|
},
|
|
286
309
|
abort: (err: Error) => {
|
|
287
310
|
log('Aborting webtransport muxer with err:', err)
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
}
|
|
311
|
+
|
|
312
|
+
for (const stream of activeStreams) {
|
|
313
|
+
stream.abort(err)
|
|
314
|
+
}
|
|
292
315
|
},
|
|
293
316
|
// This stream muxer is webtransport native. Therefore it doesn't plug in with any other duplex.
|
|
294
317
|
...inertDuplex()
|
|
@@ -307,7 +330,7 @@ class WebTransportTransport implements Transport {
|
|
|
307
330
|
* Takes a list of `Multiaddr`s and returns only valid webtransport addresses.
|
|
308
331
|
*/
|
|
309
332
|
filter (multiaddrs: Multiaddr[]): Multiaddr[] {
|
|
310
|
-
return multiaddrs.filter(
|
|
333
|
+
return multiaddrs.filter(WebTransportMatcher.exactMatch)
|
|
311
334
|
}
|
|
312
335
|
}
|
|
313
336
|
|
package/dist/typedoc-urls.json
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"WebTransportComponents": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_webtransport.WebTransportComponents.html",
|
|
3
|
-
".:WebTransportComponents": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_webtransport.WebTransportComponents.html",
|
|
4
|
-
"WebTransportInit": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_webtransport.WebTransportInit.html",
|
|
5
|
-
".:WebTransportInit": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_webtransport.WebTransportInit.html",
|
|
6
|
-
"webTransport": "https://libp2p.github.io/js-libp2p/functions/_libp2p_webtransport.webTransport.html",
|
|
7
|
-
".:webTransport": "https://libp2p.github.io/js-libp2p/functions/_libp2p_webtransport.webTransport.html"
|
|
8
|
-
}
|