libp2p 0.37.3-b1b2b21 → 0.37.3-ba56c64
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/src/circuit/circuit/hop.d.ts +3 -2
- package/dist/src/circuit/circuit/hop.d.ts.map +1 -1
- package/dist/src/circuit/circuit/hop.js +8 -4
- package/dist/src/circuit/circuit/hop.js.map +1 -1
- package/dist/src/circuit/circuit/stop.d.ts +2 -1
- package/dist/src/circuit/circuit/stop.d.ts.map +1 -1
- package/dist/src/circuit/circuit/stop.js +4 -2
- package/dist/src/circuit/circuit/stop.js.map +1 -1
- package/dist/src/circuit/index.d.ts +2 -10
- package/dist/src/circuit/index.d.ts.map +1 -1
- package/dist/src/circuit/index.js.map +1 -1
- package/dist/src/circuit/transport.d.ts +3 -0
- package/dist/src/circuit/transport.d.ts.map +1 -1
- package/dist/src/circuit/transport.js +73 -57
- package/dist/src/circuit/transport.js.map +1 -1
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +19 -4
- package/dist/src/config.js.map +1 -1
- package/dist/src/connection-manager/dialer/index.d.ts +4 -4
- package/dist/src/connection-manager/dialer/index.d.ts.map +1 -1
- package/dist/src/connection-manager/dialer/index.js +10 -10
- package/dist/src/connection-manager/dialer/index.js.map +1 -1
- package/dist/src/connection-manager/index.d.ts +15 -1
- package/dist/src/connection-manager/index.d.ts.map +1 -1
- package/dist/src/connection-manager/index.js +135 -23
- package/dist/src/connection-manager/index.js.map +1 -1
- package/dist/src/constants.d.ts +4 -0
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +4 -0
- package/dist/src/constants.js.map +1 -1
- package/dist/src/fetch/index.d.ts +4 -0
- package/dist/src/fetch/index.d.ts.map +1 -1
- package/dist/src/fetch/index.js +19 -6
- package/dist/src/fetch/index.js.map +1 -1
- package/dist/src/identify/index.d.ts +1 -1
- package/dist/src/identify/index.d.ts.map +1 -1
- package/dist/src/identify/index.js +13 -11
- package/dist/src/identify/index.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/libp2p.d.ts.map +1 -1
- package/dist/src/libp2p.js +3 -13
- package/dist/src/libp2p.js.map +1 -1
- package/dist/src/metrics/index.d.ts +2 -2
- package/dist/src/metrics/index.d.ts.map +1 -1
- package/dist/src/metrics/index.js +6 -2
- package/dist/src/metrics/index.js.map +1 -1
- package/dist/src/ping/index.d.ts +4 -0
- package/dist/src/ping/index.d.ts.map +1 -1
- package/dist/src/ping/index.js +20 -7
- package/dist/src/ping/index.js.map +1 -1
- package/dist/src/upgrader.d.ts +6 -0
- package/dist/src/upgrader.d.ts.map +1 -1
- package/dist/src/upgrader.js +83 -59
- package/dist/src/upgrader.js.map +1 -1
- package/dist/src/version.d.ts.map +1 -1
- package/dist/src/version.js.map +1 -1
- package/package.json +13 -12
- package/src/circuit/circuit/hop.ts +13 -6
- package/src/circuit/circuit/stop.ts +7 -3
- package/src/circuit/index.ts +2 -11
- package/src/circuit/transport.ts +79 -58
- package/src/config.ts +19 -4
- package/src/connection-manager/dialer/index.ts +10 -10
- package/src/connection-manager/index.ts +178 -26
- package/src/constants.ts +5 -0
- package/src/fetch/index.ts +28 -8
- package/src/identify/index.ts +16 -14
- package/src/index.ts +1 -0
- package/src/libp2p.ts +3 -14
- package/src/metrics/index.ts +8 -4
- package/src/ping/index.ts +30 -10
- package/src/upgrader.ts +95 -61
- package/src/version.ts +1 -2
package/src/config.ts
CHANGED
|
@@ -10,6 +10,7 @@ import type { Libp2pInit } from './index.js'
|
|
|
10
10
|
import { codes, messages } from './errors.js'
|
|
11
11
|
import errCode from 'err-code'
|
|
12
12
|
import type { RecursivePartial } from '@libp2p/interfaces'
|
|
13
|
+
import { isNode, isBrowser, isWebWorker, isElectronMain, isElectronRenderer, isReactNative } from 'wherearewe'
|
|
13
14
|
|
|
14
15
|
const DefaultConfig: Partial<Libp2pInit> = {
|
|
15
16
|
addresses: {
|
|
@@ -26,6 +27,7 @@ const DefaultConfig: Partial<Libp2pInit> = {
|
|
|
26
27
|
maxParallelDials: Constants.MAX_PARALLEL_DIALS,
|
|
27
28
|
maxDialsPerPeer: Constants.MAX_PER_PEER_DIALS,
|
|
28
29
|
dialTimeout: Constants.DIAL_TIMEOUT,
|
|
30
|
+
inboundUpgradeTimeout: Constants.INBOUND_UPGRADE_TIMEOUT,
|
|
29
31
|
resolvers: {
|
|
30
32
|
dnsaddr: dnsaddrResolver
|
|
31
33
|
},
|
|
@@ -67,7 +69,8 @@ const DefaultConfig: Partial<Libp2pInit> = {
|
|
|
67
69
|
},
|
|
68
70
|
hop: {
|
|
69
71
|
enabled: false,
|
|
70
|
-
active: false
|
|
72
|
+
active: false,
|
|
73
|
+
timeout: 30000
|
|
71
74
|
},
|
|
72
75
|
autoRelay: {
|
|
73
76
|
enabled: false,
|
|
@@ -79,7 +82,8 @@ const DefaultConfig: Partial<Libp2pInit> = {
|
|
|
79
82
|
host: {
|
|
80
83
|
agentVersion: AGENT_VERSION
|
|
81
84
|
},
|
|
82
|
-
|
|
85
|
+
// https://github.com/libp2p/go-libp2p/blob/8d2e54e1637041d5cf4fac1e531287560bd1f4ac/p2p/protocol/identify/id.go#L48
|
|
86
|
+
timeout: 60000,
|
|
83
87
|
maxInboundStreams: 1,
|
|
84
88
|
maxOutboundStreams: 1,
|
|
85
89
|
maxPushIncomingStreams: 1,
|
|
@@ -88,12 +92,14 @@ const DefaultConfig: Partial<Libp2pInit> = {
|
|
|
88
92
|
ping: {
|
|
89
93
|
protocolPrefix: 'ipfs',
|
|
90
94
|
maxInboundStreams: 1,
|
|
91
|
-
maxOutboundStreams: 1
|
|
95
|
+
maxOutboundStreams: 1,
|
|
96
|
+
timeout: 10000
|
|
92
97
|
},
|
|
93
98
|
fetch: {
|
|
94
99
|
protocolPrefix: 'libp2p',
|
|
95
100
|
maxInboundStreams: 1,
|
|
96
|
-
maxOutboundStreams: 1
|
|
101
|
+
maxOutboundStreams: 1,
|
|
102
|
+
timeout: 10000
|
|
97
103
|
}
|
|
98
104
|
}
|
|
99
105
|
|
|
@@ -112,5 +118,14 @@ export function validateConfig (opts: RecursivePartial<Libp2pInit>): Libp2pInit
|
|
|
112
118
|
throw errCode(new Error(messages.ERR_PROTECTOR_REQUIRED), codes.ERR_PROTECTOR_REQUIRED)
|
|
113
119
|
}
|
|
114
120
|
|
|
121
|
+
// Append user agent version to default AGENT_VERSION depending on the environment
|
|
122
|
+
if (resultingOptions.identify.host.agentVersion === AGENT_VERSION) {
|
|
123
|
+
if (isNode || isElectronMain) {
|
|
124
|
+
resultingOptions.identify.host.agentVersion += ` UserAgent=${globalThis.process.version}`
|
|
125
|
+
} else if (isBrowser || isWebWorker || isElectronRenderer || isReactNative) {
|
|
126
|
+
resultingOptions.identify.host.agentVersion += ` UserAgent=${globalThis.navigator.userAgent}`
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
115
130
|
return resultingOptions
|
|
116
131
|
}
|
|
@@ -177,7 +177,7 @@ export class Dialer implements Startable, Initializable {
|
|
|
177
177
|
|
|
178
178
|
log('creating dial target for %p', id)
|
|
179
179
|
|
|
180
|
-
const dialTarget = await this._createCancellableDialTarget(id)
|
|
180
|
+
const dialTarget = await this._createCancellableDialTarget(id, options)
|
|
181
181
|
|
|
182
182
|
if (dialTarget.addrs.length === 0) {
|
|
183
183
|
throw errCode(new Error('The dial request has no valid addresses'), codes.ERR_NO_VALID_ADDRESSES)
|
|
@@ -207,7 +207,7 @@ export class Dialer implements Startable, Initializable {
|
|
|
207
207
|
* The dial to the first address that is successfully able to upgrade a connection
|
|
208
208
|
* will be used.
|
|
209
209
|
*/
|
|
210
|
-
async _createCancellableDialTarget (peer: PeerId): Promise<DialTarget> {
|
|
210
|
+
async _createCancellableDialTarget (peer: PeerId, options: AbortOptions): Promise<DialTarget> {
|
|
211
211
|
// Make dial target promise cancellable
|
|
212
212
|
const id = `${(parseInt(String(Math.random() * 1e9), 10)).toString()}${Date.now()}`
|
|
213
213
|
const cancellablePromise = new Promise<DialTarget>((resolve, reject) => {
|
|
@@ -216,7 +216,7 @@ export class Dialer implements Startable, Initializable {
|
|
|
216
216
|
|
|
217
217
|
try {
|
|
218
218
|
const dialTarget = await Promise.race([
|
|
219
|
-
this._createDialTarget(peer),
|
|
219
|
+
this._createDialTarget(peer, options),
|
|
220
220
|
cancellablePromise
|
|
221
221
|
])
|
|
222
222
|
|
|
@@ -232,7 +232,7 @@ export class Dialer implements Startable, Initializable {
|
|
|
232
232
|
* If a multiaddr is received it should be the first address attempted.
|
|
233
233
|
* Multiaddrs not supported by the available transports will be filtered out.
|
|
234
234
|
*/
|
|
235
|
-
async _createDialTarget (peer: PeerId): Promise<DialTarget> {
|
|
235
|
+
async _createDialTarget (peer: PeerId, options: AbortOptions): Promise<DialTarget> {
|
|
236
236
|
const knownAddrs = await pipe(
|
|
237
237
|
await this.components.getPeerStore().addressBook.get(peer),
|
|
238
238
|
(source) => filter(source, async (address) => {
|
|
@@ -253,7 +253,7 @@ export class Dialer implements Startable, Initializable {
|
|
|
253
253
|
|
|
254
254
|
const addrs: Multiaddr[] = []
|
|
255
255
|
for (const a of knownAddrs) {
|
|
256
|
-
const resolvedAddrs = await this._resolve(a)
|
|
256
|
+
const resolvedAddrs = await this._resolve(a, options)
|
|
257
257
|
resolvedAddrs.forEach(ra => addrs.push(ra))
|
|
258
258
|
}
|
|
259
259
|
|
|
@@ -341,7 +341,7 @@ export class Dialer implements Startable, Initializable {
|
|
|
341
341
|
/**
|
|
342
342
|
* Resolve multiaddr recursively
|
|
343
343
|
*/
|
|
344
|
-
async _resolve (ma: Multiaddr): Promise<Multiaddr[]> {
|
|
344
|
+
async _resolve (ma: Multiaddr, options: AbortOptions): Promise<Multiaddr[]> {
|
|
345
345
|
// TODO: recursive logic should live in multiaddr once dns4/dns6 support is in place
|
|
346
346
|
// Now only supporting resolve for dnsaddr
|
|
347
347
|
const resolvableProto = ma.protoNames().includes('dnsaddr')
|
|
@@ -351,9 +351,9 @@ export class Dialer implements Startable, Initializable {
|
|
|
351
351
|
return [ma]
|
|
352
352
|
}
|
|
353
353
|
|
|
354
|
-
const resolvedMultiaddrs = await this._resolveRecord(ma)
|
|
354
|
+
const resolvedMultiaddrs = await this._resolveRecord(ma, options)
|
|
355
355
|
const recursiveMultiaddrs = await Promise.all(resolvedMultiaddrs.map(async (nm) => {
|
|
356
|
-
return await this._resolve(nm)
|
|
356
|
+
return await this._resolve(nm, options)
|
|
357
357
|
}))
|
|
358
358
|
|
|
359
359
|
const addrs = recursiveMultiaddrs.flat()
|
|
@@ -368,10 +368,10 @@ export class Dialer implements Startable, Initializable {
|
|
|
368
368
|
/**
|
|
369
369
|
* Resolve a given multiaddr. If this fails, an empty array will be returned
|
|
370
370
|
*/
|
|
371
|
-
async _resolveRecord (ma: Multiaddr): Promise<Multiaddr[]> {
|
|
371
|
+
async _resolveRecord (ma: Multiaddr, options: AbortOptions): Promise<Multiaddr[]> {
|
|
372
372
|
try {
|
|
373
373
|
ma = new Multiaddr(ma.toString()) // Use current multiaddr module
|
|
374
|
-
const multiaddrs = await ma.resolve()
|
|
374
|
+
const multiaddrs = await ma.resolve(options)
|
|
375
375
|
return multiaddrs
|
|
376
376
|
} catch (err) {
|
|
377
377
|
log.error(`multiaddr ${ma.toString()} could not be resolved`, err)
|
|
@@ -7,7 +7,6 @@ import retimer from 'retimer'
|
|
|
7
7
|
import type { AbortOptions } from '@libp2p/interfaces'
|
|
8
8
|
import { CustomEvent, EventEmitter } from '@libp2p/interfaces/events'
|
|
9
9
|
import type { Startable } from '@libp2p/interfaces/startable'
|
|
10
|
-
import { trackedMap } from '@libp2p/tracked-map'
|
|
11
10
|
import { codes } from '../errors.js'
|
|
12
11
|
import { isPeerId, PeerId } from '@libp2p/interface-peer-id'
|
|
13
12
|
import { setMaxListeners } from 'events'
|
|
@@ -19,6 +18,8 @@ import { Dialer } from './dialer/index.js'
|
|
|
19
18
|
import type { AddressSorter } from '@libp2p/interface-peer-store'
|
|
20
19
|
import type { Resolver } from '@multiformats/multiaddr'
|
|
21
20
|
import { PeerMap } from '@libp2p/peer-collections'
|
|
21
|
+
import { TimeoutController } from 'timeout-abort-controller'
|
|
22
|
+
import { KEEP_ALIVE } from '@libp2p/interface-peer-store/tags'
|
|
22
23
|
|
|
23
24
|
const log = logger('libp2p:connection-manager')
|
|
24
25
|
|
|
@@ -34,8 +35,9 @@ const defaultOptions: Partial<ConnectionManagerInit> = {
|
|
|
34
35
|
movingAverageInterval: 60000
|
|
35
36
|
}
|
|
36
37
|
|
|
38
|
+
const METRICS_SYSTEM = 'libp2p'
|
|
37
39
|
const METRICS_COMPONENT = 'connection-manager'
|
|
38
|
-
const
|
|
40
|
+
const STARTUP_RECONNECT_TIMEOUT = 60000
|
|
39
41
|
|
|
40
42
|
export interface ConnectionManagerInit {
|
|
41
43
|
/**
|
|
@@ -105,10 +107,17 @@ export interface ConnectionManagerInit {
|
|
|
105
107
|
maxAddrsToDial?: number
|
|
106
108
|
|
|
107
109
|
/**
|
|
108
|
-
* How long a dial attempt is allowed to take
|
|
110
|
+
* How long a dial attempt is allowed to take, including DNS resolution
|
|
111
|
+
* of the multiaddr, opening a socket and upgrading it to a Connection.
|
|
109
112
|
*/
|
|
110
113
|
dialTimeout?: number
|
|
111
114
|
|
|
115
|
+
/**
|
|
116
|
+
* When a new inbound connection is opened, the upgrade process (e.g. protect,
|
|
117
|
+
* encrypt, multiplex etc) must complete within this number of ms.
|
|
118
|
+
*/
|
|
119
|
+
inboundUpgradeTimeout: number
|
|
120
|
+
|
|
112
121
|
/**
|
|
113
122
|
* Number of max concurrent dials per peer
|
|
114
123
|
*/
|
|
@@ -118,6 +127,12 @@ export interface ConnectionManagerInit {
|
|
|
118
127
|
* Multiaddr resolvers to use when dialing
|
|
119
128
|
*/
|
|
120
129
|
resolvers?: Record<string, Resolver>
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* On startup we try to dial any peer that has previously been
|
|
133
|
+
* tagged with KEEP_ALIVE up to this timeout in ms. (default: 60000)
|
|
134
|
+
*/
|
|
135
|
+
startupReconnectTimeout?: number
|
|
121
136
|
}
|
|
122
137
|
|
|
123
138
|
export interface ConnectionManagerEvents {
|
|
@@ -136,6 +151,9 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
136
151
|
private started: boolean
|
|
137
152
|
private timer?: ReturnType<retimer>
|
|
138
153
|
private readonly latencyMonitor: LatencyMonitor
|
|
154
|
+
private readonly startupReconnectTimeout: number
|
|
155
|
+
private connectOnStartupController?: TimeoutController
|
|
156
|
+
private readonly dialTimeout: number
|
|
139
157
|
|
|
140
158
|
constructor (init: ConnectionManagerInit) {
|
|
141
159
|
super()
|
|
@@ -151,11 +169,7 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
151
169
|
/**
|
|
152
170
|
* Map of connections per peer
|
|
153
171
|
*/
|
|
154
|
-
this.connections =
|
|
155
|
-
component: METRICS_COMPONENT,
|
|
156
|
-
metric: METRICS_PEER_CONNECTIONS,
|
|
157
|
-
metrics: this.components.getMetrics()
|
|
158
|
-
})
|
|
172
|
+
this.connections = new Map()
|
|
159
173
|
|
|
160
174
|
this.started = false
|
|
161
175
|
this._checkMetrics = this._checkMetrics.bind(this)
|
|
@@ -174,12 +188,103 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
174
188
|
|
|
175
189
|
this.onConnect = this.onConnect.bind(this)
|
|
176
190
|
this.onDisconnect = this.onDisconnect.bind(this)
|
|
191
|
+
|
|
192
|
+
this.startupReconnectTimeout = init.startupReconnectTimeout ?? STARTUP_RECONNECT_TIMEOUT
|
|
193
|
+
this.dialTimeout = init.dialTimeout ?? 30000
|
|
177
194
|
}
|
|
178
195
|
|
|
179
196
|
init (components: Components): void {
|
|
180
197
|
this.components = components
|
|
181
198
|
|
|
182
199
|
this.dialer.init(components)
|
|
200
|
+
|
|
201
|
+
// track inbound/outbound connections
|
|
202
|
+
this.components.getMetrics()?.updateComponentMetric({
|
|
203
|
+
system: METRICS_SYSTEM,
|
|
204
|
+
component: METRICS_COMPONENT,
|
|
205
|
+
metric: 'connections',
|
|
206
|
+
label: 'direction',
|
|
207
|
+
value: () => {
|
|
208
|
+
const metric = {
|
|
209
|
+
inbound: 0,
|
|
210
|
+
outbound: 0
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
for (const conns of this.connections.values()) {
|
|
214
|
+
for (const conn of conns) {
|
|
215
|
+
if (conn.stat.direction === 'inbound') {
|
|
216
|
+
metric.inbound++
|
|
217
|
+
} else {
|
|
218
|
+
metric.outbound++
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return metric
|
|
224
|
+
}
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
// track total number of streams per protocol
|
|
228
|
+
this.components.getMetrics()?.updateComponentMetric({
|
|
229
|
+
system: METRICS_SYSTEM,
|
|
230
|
+
component: METRICS_COMPONENT,
|
|
231
|
+
metric: 'protocol-streams-total',
|
|
232
|
+
label: 'protocol',
|
|
233
|
+
value: () => {
|
|
234
|
+
const metric: Record<string, number> = {}
|
|
235
|
+
|
|
236
|
+
for (const conns of this.connections.values()) {
|
|
237
|
+
for (const conn of conns) {
|
|
238
|
+
for (const stream of conn.streams) {
|
|
239
|
+
const key = `${stream.stat.direction} ${stream.stat.protocol ?? 'unnegotiated'}`
|
|
240
|
+
|
|
241
|
+
metric[key] = (metric[key] ?? 0) + 1
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return metric
|
|
247
|
+
}
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
// track 90th percentile of streams per protocol
|
|
251
|
+
this.components.getMetrics()?.updateComponentMetric({
|
|
252
|
+
system: METRICS_SYSTEM,
|
|
253
|
+
component: METRICS_COMPONENT,
|
|
254
|
+
metric: 'protocol-streams-per-connection-90th-percentile',
|
|
255
|
+
label: 'protocol',
|
|
256
|
+
value: () => {
|
|
257
|
+
const allStreams: Record<string, number[]> = {}
|
|
258
|
+
|
|
259
|
+
for (const conns of this.connections.values()) {
|
|
260
|
+
for (const conn of conns) {
|
|
261
|
+
const streams: Record<string, number> = {}
|
|
262
|
+
|
|
263
|
+
for (const stream of conn.streams) {
|
|
264
|
+
const key = `${stream.stat.direction} ${stream.stat.protocol ?? 'unnegotiated'}`
|
|
265
|
+
|
|
266
|
+
streams[key] = (streams[key] ?? 0) + 1
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
for (const [protocol, count] of Object.entries(streams)) {
|
|
270
|
+
allStreams[protocol] = allStreams[protocol] ?? []
|
|
271
|
+
allStreams[protocol].push(count)
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const metric: Record<string, number> = {}
|
|
277
|
+
|
|
278
|
+
for (let [protocol, counts] of Object.entries(allStreams)) {
|
|
279
|
+
counts = counts.sort((a, b) => a - b)
|
|
280
|
+
|
|
281
|
+
const index = Math.floor(counts.length * 0.9)
|
|
282
|
+
metric[protocol] = counts[index]
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return metric
|
|
286
|
+
}
|
|
287
|
+
})
|
|
183
288
|
}
|
|
184
289
|
|
|
185
290
|
isStarted () {
|
|
@@ -208,9 +313,43 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
208
313
|
async afterStart () {
|
|
209
314
|
this.components.getUpgrader().addEventListener('connection', this.onConnect)
|
|
210
315
|
this.components.getUpgrader().addEventListener('connectionEnd', this.onDisconnect)
|
|
316
|
+
|
|
317
|
+
// re-connect to any peers with the KEEP_ALIVE tag
|
|
318
|
+
void Promise.resolve()
|
|
319
|
+
.then(async () => {
|
|
320
|
+
const keepAlivePeers: PeerId[] = []
|
|
321
|
+
|
|
322
|
+
for (const peer of await this.components.getPeerStore().all()) {
|
|
323
|
+
const tags = await this.components.getPeerStore().getTags(peer.id)
|
|
324
|
+
const hasKeepAlive = tags.filter(tag => tag.name === KEEP_ALIVE).length > 0
|
|
325
|
+
|
|
326
|
+
if (hasKeepAlive) {
|
|
327
|
+
keepAlivePeers.push(peer.id)
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
this.connectOnStartupController?.clear()
|
|
332
|
+
this.connectOnStartupController = new TimeoutController(this.startupReconnectTimeout)
|
|
333
|
+
|
|
334
|
+
await Promise.all(
|
|
335
|
+
keepAlivePeers.map(async peer => {
|
|
336
|
+
await this.openConnection(peer, {
|
|
337
|
+
signal: this.connectOnStartupController?.signal
|
|
338
|
+
})
|
|
339
|
+
.catch(err => {
|
|
340
|
+
log.error(err)
|
|
341
|
+
})
|
|
342
|
+
})
|
|
343
|
+
)
|
|
344
|
+
})
|
|
345
|
+
.finally(() => {
|
|
346
|
+
this.connectOnStartupController?.clear()
|
|
347
|
+
})
|
|
211
348
|
}
|
|
212
349
|
|
|
213
350
|
async beforeStop () {
|
|
351
|
+
// if we are still dialing KEEP_ALIVE peers, abort those dials
|
|
352
|
+
this.connectOnStartupController?.abort()
|
|
214
353
|
this.components.getUpgrader().removeEventListener('connection', this.onConnect)
|
|
215
354
|
this.components.getUpgrader().removeEventListener('connectionEnd', this.onDisconnect)
|
|
216
355
|
}
|
|
@@ -356,7 +495,7 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
356
495
|
return conns
|
|
357
496
|
}
|
|
358
497
|
|
|
359
|
-
async openConnection (peerId: PeerId, options
|
|
498
|
+
async openConnection (peerId: PeerId, options: AbortOptions = {}): Promise<Connection> {
|
|
360
499
|
log('dial to %p', peerId)
|
|
361
500
|
const existingConnections = this.getConnections(peerId)
|
|
362
501
|
|
|
@@ -366,30 +505,43 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
366
505
|
return existingConnections[0]
|
|
367
506
|
}
|
|
368
507
|
|
|
369
|
-
|
|
370
|
-
let peerConnections = this.connections.get(peerId.toString())
|
|
508
|
+
let timeoutController: TimeoutController | undefined
|
|
371
509
|
|
|
372
|
-
if (
|
|
373
|
-
|
|
374
|
-
|
|
510
|
+
if (options?.signal == null) {
|
|
511
|
+
timeoutController = new TimeoutController(this.dialTimeout)
|
|
512
|
+
options.signal = timeoutController.signal
|
|
375
513
|
}
|
|
376
514
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
let trackedConnection = false
|
|
515
|
+
try {
|
|
516
|
+
const connection = await this.dialer.dial(peerId, options)
|
|
517
|
+
let peerConnections = this.connections.get(peerId.toString())
|
|
381
518
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
519
|
+
if (peerConnections == null) {
|
|
520
|
+
peerConnections = []
|
|
521
|
+
this.connections.set(peerId.toString(), peerConnections)
|
|
385
522
|
}
|
|
386
|
-
}
|
|
387
523
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
524
|
+
// we get notified of connections via the Upgrader emitting "connection"
|
|
525
|
+
// events, double check we aren't already tracking this connection before
|
|
526
|
+
// storing it
|
|
527
|
+
let trackedConnection = false
|
|
391
528
|
|
|
392
|
-
|
|
529
|
+
for (const conn of peerConnections) {
|
|
530
|
+
if (conn.id === connection.id) {
|
|
531
|
+
trackedConnection = true
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
if (!trackedConnection) {
|
|
536
|
+
peerConnections.push(connection)
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
return connection
|
|
540
|
+
} finally {
|
|
541
|
+
if (timeoutController != null) {
|
|
542
|
+
timeoutController.clear()
|
|
543
|
+
}
|
|
544
|
+
}
|
|
393
545
|
}
|
|
394
546
|
|
|
395
547
|
async closeConnections (peerId: PeerId): Promise<void> {
|
package/src/constants.ts
CHANGED
package/src/fetch/index.ts
CHANGED
|
@@ -10,10 +10,10 @@ import type { Stream } from '@libp2p/interface-connection'
|
|
|
10
10
|
import type { IncomingStreamData } from '@libp2p/interface-registrar'
|
|
11
11
|
import type { Components } from '@libp2p/components'
|
|
12
12
|
import type { AbortOptions } from '@libp2p/interfaces'
|
|
13
|
-
import type { Duplex } from 'it-stream-types'
|
|
14
13
|
import { abortableDuplex } from 'abortable-iterator'
|
|
15
14
|
import { pipe } from 'it-pipe'
|
|
16
15
|
import first from 'it-first'
|
|
16
|
+
import { TimeoutController } from 'timeout-abort-controller'
|
|
17
17
|
|
|
18
18
|
const log = logger('libp2p:fetch')
|
|
19
19
|
|
|
@@ -21,6 +21,11 @@ export interface FetchServiceInit {
|
|
|
21
21
|
protocolPrefix: string
|
|
22
22
|
maxInboundStreams: number
|
|
23
23
|
maxOutboundStreams: number
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* How long we should wait for a remote peer to send any data
|
|
27
|
+
*/
|
|
28
|
+
timeout: number
|
|
24
29
|
}
|
|
25
30
|
|
|
26
31
|
export interface HandleMessageOptions {
|
|
@@ -86,15 +91,24 @@ export class FetchService implements Startable {
|
|
|
86
91
|
log('dialing %s to %p', this.protocol, peer)
|
|
87
92
|
|
|
88
93
|
const connection = await this.components.getConnectionManager().openConnection(peer, options)
|
|
89
|
-
|
|
90
|
-
let
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if
|
|
94
|
-
|
|
94
|
+
let timeoutController
|
|
95
|
+
let signal = options.signal
|
|
96
|
+
let stream: Stream | undefined
|
|
97
|
+
|
|
98
|
+
// create a timeout if no abort signal passed
|
|
99
|
+
if (signal == null) {
|
|
100
|
+
timeoutController = new TimeoutController(this.init.timeout)
|
|
101
|
+
signal = timeoutController.signal
|
|
95
102
|
}
|
|
96
103
|
|
|
97
104
|
try {
|
|
105
|
+
stream = await connection.newStream([this.protocol], {
|
|
106
|
+
signal
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
// make stream abortable
|
|
110
|
+
const source = abortableDuplex(stream, signal)
|
|
111
|
+
|
|
98
112
|
const result = await pipe(
|
|
99
113
|
[FetchRequest.encode({ identifier: key })],
|
|
100
114
|
lp.encode(),
|
|
@@ -129,7 +143,13 @@ export class FetchService implements Startable {
|
|
|
129
143
|
|
|
130
144
|
return result ?? null
|
|
131
145
|
} finally {
|
|
132
|
-
|
|
146
|
+
if (timeoutController != null) {
|
|
147
|
+
timeoutController.clear()
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (stream != null) {
|
|
151
|
+
stream.close()
|
|
152
|
+
}
|
|
133
153
|
}
|
|
134
154
|
}
|
|
135
155
|
|
package/src/identify/index.ts
CHANGED
|
@@ -30,9 +30,6 @@ import type { Duplex } from 'it-stream-types'
|
|
|
30
30
|
|
|
31
31
|
const log = logger('libp2p:identify')
|
|
32
32
|
|
|
33
|
-
// https://github.com/libp2p/go-libp2p/blob/8d2e54e1637041d5cf4fac1e531287560bd1f4ac/p2p/protocol/identify/id.go#L48
|
|
34
|
-
const IDENTIFY_TIMEOUT = 60000
|
|
35
|
-
|
|
36
33
|
// https://github.com/libp2p/go-libp2p/blob/8d2e54e1637041d5cf4fac1e531287560bd1f4ac/p2p/protocol/identify/id.go#L52
|
|
37
34
|
const MAX_IDENTIFY_MESSAGE_SIZE = 1024 * 8
|
|
38
35
|
|
|
@@ -54,7 +51,7 @@ export interface IdentifyServiceInit {
|
|
|
54
51
|
/**
|
|
55
52
|
* How long we should wait for a remote peer to send their identify response
|
|
56
53
|
*/
|
|
57
|
-
timeout
|
|
54
|
+
timeout: number
|
|
58
55
|
|
|
59
56
|
/**
|
|
60
57
|
* Identify responses larger than this in bytes will be rejected (default: 8192)
|
|
@@ -167,7 +164,7 @@ export class IdentifyService implements Startable {
|
|
|
167
164
|
const protocols = await this.components.getPeerStore().protoBook.get(this.components.getPeerId())
|
|
168
165
|
|
|
169
166
|
const pushes = connections.map(async connection => {
|
|
170
|
-
const timeoutController = new TimeoutController(this.init.timeout
|
|
167
|
+
const timeoutController = new TimeoutController(this.init.timeout)
|
|
171
168
|
let stream: Stream | undefined
|
|
172
169
|
|
|
173
170
|
try {
|
|
@@ -229,21 +226,24 @@ export class IdentifyService implements Startable {
|
|
|
229
226
|
}
|
|
230
227
|
|
|
231
228
|
async _identify (connection: Connection, options: AbortOptions = {}): Promise<Identify> {
|
|
232
|
-
const stream = await connection.newStream([this.identifyProtocolStr], options)
|
|
233
|
-
let source: Duplex<Uint8Array> = stream
|
|
234
229
|
let timeoutController
|
|
235
230
|
let signal = options.signal
|
|
231
|
+
let stream: Stream | undefined
|
|
236
232
|
|
|
237
233
|
// create a timeout if no abort signal passed
|
|
238
234
|
if (signal == null) {
|
|
239
|
-
timeoutController = new TimeoutController(this.init.timeout
|
|
235
|
+
timeoutController = new TimeoutController(this.init.timeout)
|
|
240
236
|
signal = timeoutController.signal
|
|
241
237
|
}
|
|
242
238
|
|
|
243
|
-
// make stream abortable if AbortSignal passed
|
|
244
|
-
source = abortableDuplex(stream, signal)
|
|
245
|
-
|
|
246
239
|
try {
|
|
240
|
+
stream = await connection.newStream([this.identifyProtocolStr], {
|
|
241
|
+
signal
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
// make stream abortable
|
|
245
|
+
const source = abortableDuplex(stream, signal)
|
|
246
|
+
|
|
247
247
|
const data = await pipe(
|
|
248
248
|
[],
|
|
249
249
|
source,
|
|
@@ -267,7 +267,9 @@ export class IdentifyService implements Startable {
|
|
|
267
267
|
timeoutController.clear()
|
|
268
268
|
}
|
|
269
269
|
|
|
270
|
-
stream
|
|
270
|
+
if (stream != null) {
|
|
271
|
+
stream.close()
|
|
272
|
+
}
|
|
271
273
|
}
|
|
272
274
|
}
|
|
273
275
|
|
|
@@ -370,7 +372,7 @@ export class IdentifyService implements Startable {
|
|
|
370
372
|
*/
|
|
371
373
|
async _handleIdentify (data: IncomingStreamData) {
|
|
372
374
|
const { connection, stream } = data
|
|
373
|
-
const timeoutController = new TimeoutController(this.init.timeout
|
|
375
|
+
const timeoutController = new TimeoutController(this.init.timeout)
|
|
374
376
|
|
|
375
377
|
try {
|
|
376
378
|
const publicKey = this.components.getPeerId().publicKey ?? new Uint8Array(0)
|
|
@@ -421,7 +423,7 @@ export class IdentifyService implements Startable {
|
|
|
421
423
|
*/
|
|
422
424
|
async _handlePush (data: IncomingStreamData) {
|
|
423
425
|
const { connection, stream } = data
|
|
424
|
-
const timeoutController = new TimeoutController(this.init.timeout
|
|
426
|
+
const timeoutController = new TimeoutController(this.init.timeout)
|
|
425
427
|
|
|
426
428
|
let message: Identify | undefined
|
|
427
429
|
try {
|
package/src/index.ts
CHANGED
package/src/libp2p.ts
CHANGED
|
@@ -124,7 +124,8 @@ export class Libp2pNode extends EventEmitter<Libp2pEvents> implements Libp2p {
|
|
|
124
124
|
// Set up the Upgrader
|
|
125
125
|
this.components.setUpgrader(new DefaultUpgrader(this.components, {
|
|
126
126
|
connectionEncryption: (init.connectionEncryption ?? []).map(component => this.configureComponent(component)),
|
|
127
|
-
muxers: (init.streamMuxers ?? []).map(component => this.configureComponent(component))
|
|
127
|
+
muxers: (init.streamMuxers ?? []).map(component => this.configureComponent(component)),
|
|
128
|
+
inboundUpgradeTimeout: init.connectionManager.inboundUpgradeTimeout
|
|
128
129
|
}))
|
|
129
130
|
|
|
130
131
|
// Create the Connection Manager
|
|
@@ -217,7 +218,7 @@ export class Libp2pNode extends EventEmitter<Libp2pEvents> implements Libp2p {
|
|
|
217
218
|
})))
|
|
218
219
|
|
|
219
220
|
if (init.relay.enabled) {
|
|
220
|
-
this.components.getTransportManager().add(this.configureComponent(new Circuit()))
|
|
221
|
+
this.components.getTransportManager().add(this.configureComponent(new Circuit(init.relay)))
|
|
221
222
|
|
|
222
223
|
this.configureComponent(new Relay(this.components, {
|
|
223
224
|
addressSorter: init.connectionManager.addressSorter,
|
|
@@ -309,18 +310,6 @@ export class Libp2pNode extends EventEmitter<Libp2pEvents> implements Libp2p {
|
|
|
309
310
|
)
|
|
310
311
|
|
|
311
312
|
log('libp2p has started')
|
|
312
|
-
|
|
313
|
-
// Once we start, emit any peers we may have already discovered
|
|
314
|
-
// TODO: this should be removed, as we already discovered these peers in the past
|
|
315
|
-
await this.components.getPeerStore().forEach(peer => {
|
|
316
|
-
this.dispatchEvent(new CustomEvent<PeerInfo>('peer:discovery', {
|
|
317
|
-
detail: {
|
|
318
|
-
id: peer.id,
|
|
319
|
-
multiaddrs: peer.addresses.map(addr => addr.multiaddr),
|
|
320
|
-
protocols: peer.protocols
|
|
321
|
-
}
|
|
322
|
-
}))
|
|
323
|
-
})
|
|
324
313
|
} catch (err: any) {
|
|
325
314
|
log.error('An error occurred starting libp2p', err)
|
|
326
315
|
await this.stop()
|