libp2p 2.9.0 → 2.10.0-8484de8a2
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 +13 -17
- package/dist/index.min.js.map +4 -4
- package/dist/src/address-manager/dns-mappings.d.ts +1 -2
- package/dist/src/address-manager/dns-mappings.d.ts.map +1 -1
- package/dist/src/address-manager/dns-mappings.js +40 -44
- package/dist/src/address-manager/dns-mappings.js.map +1 -1
- package/dist/src/address-manager/index.d.ts.map +1 -1
- package/dist/src/address-manager/index.js +31 -14
- package/dist/src/address-manager/index.js.map +1 -1
- package/dist/src/address-manager/ip-mappings.d.ts +1 -0
- package/dist/src/address-manager/ip-mappings.d.ts.map +1 -1
- package/dist/src/address-manager/ip-mappings.js +51 -40
- package/dist/src/address-manager/ip-mappings.js.map +1 -1
- package/dist/src/address-manager/observed-addresses.d.ts.map +1 -1
- package/dist/src/address-manager/observed-addresses.js +1 -3
- package/dist/src/address-manager/observed-addresses.js.map +1 -1
- package/dist/src/address-manager/transport-addresses.d.ts.map +1 -1
- package/dist/src/address-manager/transport-addresses.js +6 -8
- package/dist/src/address-manager/transport-addresses.js.map +1 -1
- package/dist/src/config/connection-gater.browser.d.ts.map +1 -1
- package/dist/src/config/connection-gater.browser.js +3 -9
- package/dist/src/config/connection-gater.browser.js.map +1 -1
- package/dist/src/config.js +1 -1
- package/dist/src/config.js.map +1 -1
- package/dist/src/connection-manager/address-sorter.d.ts.map +1 -1
- package/dist/src/connection-manager/address-sorter.js +1 -2
- package/dist/src/connection-manager/address-sorter.js.map +1 -1
- package/dist/src/connection-manager/connection-pruner.d.ts.map +1 -1
- package/dist/src/connection-manager/connection-pruner.js +7 -3
- package/dist/src/connection-manager/connection-pruner.js.map +1 -1
- package/dist/src/connection-manager/constants.defaults.d.ts +4 -0
- package/dist/src/connection-manager/constants.defaults.d.ts.map +1 -1
- package/dist/src/connection-manager/constants.defaults.js +4 -0
- package/dist/src/connection-manager/constants.defaults.js.map +1 -1
- package/dist/src/connection-manager/dial-queue.d.ts +2 -2
- package/dist/src/connection-manager/dial-queue.d.ts.map +1 -1
- package/dist/src/connection-manager/dial-queue.js +13 -25
- package/dist/src/connection-manager/dial-queue.js.map +1 -1
- package/dist/src/connection-manager/index.d.ts +10 -2
- package/dist/src/connection-manager/index.d.ts.map +1 -1
- package/dist/src/connection-manager/index.js +45 -27
- package/dist/src/connection-manager/index.js.map +1 -1
- package/dist/src/connection-manager/reconnect-queue.js +1 -1
- package/dist/src/connection-manager/reconnect-queue.js.map +1 -1
- package/dist/src/connection-manager/utils.d.ts +31 -3
- package/dist/src/connection-manager/utils.d.ts.map +1 -1
- package/dist/src/connection-manager/utils.js +99 -18
- package/dist/src/connection-manager/utils.js.map +1 -1
- package/dist/src/connection-monitor.d.ts +1 -1
- package/dist/src/connection-monitor.d.ts.map +1 -1
- package/dist/src/connection-monitor.js +2 -3
- package/dist/src/connection-monitor.js.map +1 -1
- package/dist/src/connection.d.ts +62 -0
- package/dist/src/connection.d.ts.map +1 -0
- package/dist/src/connection.js +239 -0
- package/dist/src/connection.js.map +1 -0
- package/dist/src/get-peer.js +3 -3
- package/dist/src/get-peer.js.map +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.js +2 -2
- package/dist/src/libp2p.d.ts.map +1 -1
- package/dist/src/libp2p.js +5 -5
- package/dist/src/libp2p.js.map +1 -1
- package/dist/src/peer-routing.js +1 -1
- package/dist/src/peer-routing.js.map +1 -1
- package/dist/src/random-walk.d.ts.map +1 -1
- package/dist/src/random-walk.js +13 -3
- package/dist/src/random-walk.js.map +1 -1
- package/dist/src/registrar.d.ts +3 -3
- package/dist/src/registrar.d.ts.map +1 -1
- package/dist/src/registrar.js +50 -41
- package/dist/src/registrar.js.map +1 -1
- package/dist/src/transport-manager.js +15 -2
- package/dist/src/transport-manager.js.map +1 -1
- package/dist/src/upgrader.d.ts +27 -25
- package/dist/src/upgrader.d.ts.map +1 -1
- package/dist/src/upgrader.js +97 -336
- package/dist/src/upgrader.js.map +1 -1
- package/dist/src/utils.d.ts +3 -0
- package/dist/src/utils.d.ts.map +1 -0
- package/dist/src/utils.js +25 -0
- package/dist/src/utils.js.map +1 -0
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.d.ts.map +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/version.js.map +1 -1
- package/package.json +26 -30
- package/src/address-manager/dns-mappings.ts +51 -51
- package/src/address-manager/index.ts +37 -17
- package/src/address-manager/ip-mappings.ts +64 -44
- package/src/address-manager/observed-addresses.ts +1 -3
- package/src/address-manager/transport-addresses.ts +7 -9
- package/src/config/connection-gater.browser.ts +3 -12
- package/src/config.ts +1 -1
- package/src/connection-manager/address-sorter.ts +1 -2
- package/src/connection-manager/connection-pruner.ts +8 -3
- package/src/connection-manager/constants.defaults.ts +5 -0
- package/src/connection-manager/dial-queue.ts +14 -29
- package/src/connection-manager/index.ts +62 -29
- package/src/connection-manager/reconnect-queue.ts +1 -1
- package/src/connection-manager/utils.ts +129 -21
- package/src/connection-monitor.ts +3 -4
- package/src/connection.ts +316 -0
- package/src/get-peer.ts +3 -3
- package/src/index.ts +2 -2
- package/src/libp2p.ts +5 -6
- package/src/peer-routing.ts +1 -1
- package/src/random-walk.ts +13 -3
- package/src/registrar.ts +67 -54
- package/src/transport-manager.ts +18 -2
- package/src/upgrader.ts +143 -421
- package/src/utils.ts +31 -0
- package/src/version.ts +1 -1
- package/dist/src/connection/index.d.ts +0 -84
- package/dist/src/connection/index.d.ts.map +0 -1
- package/dist/src/connection/index.js +0 -144
- package/dist/src/connection/index.js.map +0 -1
- package/dist/typedoc-urls.json +0 -24
- package/src/connection/index.ts +0 -199
|
@@ -1,38 +1,146 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
1
|
+
import { IpNet } from '@chainsafe/netmask'
|
|
2
|
+
import { InvalidParametersError } from '@libp2p/interface'
|
|
3
|
+
import { getNetConfig } from '@libp2p/utils'
|
|
4
|
+
import { Circuit } from '@multiformats/multiaddr-matcher'
|
|
5
|
+
import type { Connection, AbortOptions, PeerId } from '@libp2p/interface'
|
|
4
6
|
import type { Multiaddr } from '@multiformats/multiaddr'
|
|
5
7
|
|
|
8
|
+
/**
|
|
9
|
+
* These are speculative protocols that are run automatically on connection open
|
|
10
|
+
* so are usually not the reason the connection was opened.
|
|
11
|
+
*
|
|
12
|
+
* Consequently when requested it should be safe to close connections that only
|
|
13
|
+
* have these protocol streams open.
|
|
14
|
+
*/
|
|
15
|
+
const DEFAULT_CLOSABLE_PROTOCOLS = [
|
|
16
|
+
// identify
|
|
17
|
+
'/ipfs/id/1.0.0',
|
|
18
|
+
|
|
19
|
+
// identify-push
|
|
20
|
+
'/ipfs/id/push/1.0.0',
|
|
21
|
+
|
|
22
|
+
// autonat
|
|
23
|
+
'/libp2p/autonat/1.0.0',
|
|
24
|
+
|
|
25
|
+
// dcutr
|
|
26
|
+
'/libp2p/dcutr'
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
export interface SafelyCloseConnectionOptions extends AbortOptions {
|
|
30
|
+
/**
|
|
31
|
+
* Only close the stream if it either has no protocol streams open or only
|
|
32
|
+
* ones in this list.
|
|
33
|
+
*
|
|
34
|
+
* @default ['/ipfs/id/1.0.0']
|
|
35
|
+
*/
|
|
36
|
+
closableProtocols?: string[]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Close the passed connection if it has no streams, or only closable protocol
|
|
41
|
+
* streams, falling back to aborting the connection if closing it cleanly fails.
|
|
42
|
+
*/
|
|
43
|
+
export async function safelyCloseConnectionIfUnused (connection?: Connection, options?: SafelyCloseConnectionOptions): Promise<void> {
|
|
44
|
+
const streamProtocols = connection?.streams?.map(stream => stream.protocol) ?? []
|
|
45
|
+
const closableProtocols = options?.closableProtocols ?? DEFAULT_CLOSABLE_PROTOCOLS
|
|
46
|
+
|
|
47
|
+
// if the connection has protocols not in the closable protocols list, do not
|
|
48
|
+
// close the connection
|
|
49
|
+
if (streamProtocols.filter(proto => proto != null && !closableProtocols.includes(proto)).length > 0) {
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
await connection?.close(options)
|
|
55
|
+
} catch (err: any) {
|
|
56
|
+
connection?.abort(err)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
6
60
|
/**
|
|
7
61
|
* Converts a multiaddr string or object to an IpNet object.
|
|
8
62
|
* If the multiaddr doesn't include /ipcidr, it will encapsulate with the appropriate CIDR:
|
|
9
63
|
* - /ipcidr/32 for IPv4
|
|
10
64
|
* - /ipcidr/128 for IPv6
|
|
11
65
|
*
|
|
12
|
-
* @param {string | Multiaddr} ma - The multiaddr
|
|
66
|
+
* @param {string | Multiaddr} ma - The multiaddr object to convert.
|
|
13
67
|
* @returns {IpNet} The converted IpNet object.
|
|
14
68
|
* @throws {Error} Throws an error if the multiaddr is not valid.
|
|
15
69
|
*/
|
|
16
|
-
export function multiaddrToIpNet (ma:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
if (typeof ma === 'string') {
|
|
20
|
-
parsedMa = multiaddr(ma)
|
|
21
|
-
} else {
|
|
22
|
-
parsedMa = ma
|
|
23
|
-
}
|
|
70
|
+
export function multiaddrToIpNet (ma: Multiaddr): IpNet {
|
|
71
|
+
const config = getNetConfig(ma)
|
|
72
|
+
let mask = config.cidr
|
|
24
73
|
|
|
25
|
-
|
|
74
|
+
if (config.type !== 'ip4' && config.type !== 'ip6') {
|
|
75
|
+
throw new InvalidParametersError(`Multiaddr ${ma} was not an IPv4 or IPv6 address`)
|
|
76
|
+
}
|
|
26
77
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
78
|
+
// Check if /ipcidr is already present
|
|
79
|
+
if (mask == null) {
|
|
80
|
+
switch (config.type) {
|
|
81
|
+
case 'ip4': {
|
|
82
|
+
mask = 32
|
|
83
|
+
break
|
|
84
|
+
}
|
|
85
|
+
case 'ip6': {
|
|
86
|
+
mask = 128
|
|
87
|
+
break
|
|
88
|
+
}
|
|
89
|
+
default: {
|
|
90
|
+
throw new InvalidParametersError(`Multiaddr ${ma} was not an IPv4 or IPv6 address`)
|
|
91
|
+
}
|
|
32
92
|
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return new IpNet(config.host, mask)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Returns true if the passed multiaddr would result in a direct connection to
|
|
100
|
+
* the peer.
|
|
101
|
+
*
|
|
102
|
+
* Currently only circuit relay addresses are supported as indirect connections.
|
|
103
|
+
*/
|
|
104
|
+
export function isDirect (ma: Multiaddr): boolean {
|
|
105
|
+
return !Circuit.exactMatch(ma)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* If there is an existing non-limited connection to the remote peer return it,
|
|
110
|
+
* unless it is indirect and at least one of the passed dial addresses would
|
|
111
|
+
* result in a direct connection
|
|
112
|
+
*/
|
|
113
|
+
export function findExistingConnection (peerId?: PeerId, connections?: Connection[], dialAddresses?: Multiaddr[]): Connection | undefined {
|
|
114
|
+
if (peerId == null || connections == null) {
|
|
115
|
+
return
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const existingConnection = connections
|
|
119
|
+
.sort((a, b) => {
|
|
120
|
+
if (a.direct) {
|
|
121
|
+
return -1
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (b.direct) {
|
|
125
|
+
return 1
|
|
126
|
+
}
|
|
33
127
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
128
|
+
return 0
|
|
129
|
+
})
|
|
130
|
+
.find(con => con.limits == null)
|
|
131
|
+
|
|
132
|
+
if (existingConnection == null || existingConnection.direct || dialAddresses == null) {
|
|
133
|
+
return existingConnection
|
|
37
134
|
}
|
|
135
|
+
|
|
136
|
+
// we have an indirect, but unlimited connection - test the dial addresses to
|
|
137
|
+
// see if any of them would result in a direct connection, in which case allow
|
|
138
|
+
// the attempt to upgrade to a direct connection
|
|
139
|
+
const wouldUpgradeToDirect = dialAddresses.some(ma => isDirect(ma))
|
|
140
|
+
|
|
141
|
+
if (wouldUpgradeToDirect) {
|
|
142
|
+
return
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return existingConnection
|
|
38
146
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { randomBytes } from '@libp2p/crypto'
|
|
2
2
|
import { serviceCapabilities } from '@libp2p/interface'
|
|
3
|
-
import { AdaptiveTimeout } from '@libp2p/utils
|
|
4
|
-
import { byteStream } from 'it-byte-stream'
|
|
3
|
+
import { AdaptiveTimeout, byteStream } from '@libp2p/utils'
|
|
5
4
|
import { setMaxListeners } from 'main-event'
|
|
6
5
|
import type { ComponentLogger, Logger, Metrics, Startable } from '@libp2p/interface'
|
|
7
6
|
import type { ConnectionManager } from '@libp2p/interface-internal'
|
|
8
|
-
import type { AdaptiveTimeoutInit } from '@libp2p/utils
|
|
7
|
+
import type { AdaptiveTimeoutInit } from '@libp2p/utils'
|
|
9
8
|
|
|
10
9
|
const DEFAULT_PING_INTERVAL_MS = 10000
|
|
11
10
|
const PROTOCOL_VERSION = '1.0.0'
|
|
@@ -120,7 +119,7 @@ export class ConnectionMonitor implements Startable {
|
|
|
120
119
|
|
|
121
120
|
conn.rtt = Date.now() - start
|
|
122
121
|
|
|
123
|
-
await
|
|
122
|
+
await stream.close({
|
|
124
123
|
signal
|
|
125
124
|
})
|
|
126
125
|
} catch (err: any) {
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import { connectionSymbol, LimitedConnectionError, ConnectionClosedError, TooManyOutboundProtocolStreamsError, TooManyInboundProtocolStreamsError, StreamCloseEvent } from '@libp2p/interface'
|
|
2
|
+
import * as mss from '@libp2p/multistream-select'
|
|
3
|
+
import { CODE_P2P } from '@multiformats/multiaddr'
|
|
4
|
+
import { setMaxListeners, TypedEventEmitter } from 'main-event'
|
|
5
|
+
import { CONNECTION_CLOSE_TIMEOUT, PROTOCOL_NEGOTIATION_TIMEOUT } from './connection-manager/constants.defaults.ts'
|
|
6
|
+
import { isDirect } from './connection-manager/utils.ts'
|
|
7
|
+
import { MuxerUnavailableError } from './errors.ts'
|
|
8
|
+
import { DEFAULT_MAX_INBOUND_STREAMS, DEFAULT_MAX_OUTBOUND_STREAMS } from './registrar.ts'
|
|
9
|
+
import type { AbortOptions, Logger, MessageStreamDirection, Connection as ConnectionInterface, Stream, NewStreamOptions, PeerId, ConnectionLimits, StreamMuxer, Metrics, PeerStore, MultiaddrConnection, MessageStreamEvents, MultiaddrConnectionTimeline, ConnectionStatus, MessageStream } from '@libp2p/interface'
|
|
10
|
+
import type { Registrar } from '@libp2p/interface-internal'
|
|
11
|
+
import type { Multiaddr } from '@multiformats/multiaddr'
|
|
12
|
+
|
|
13
|
+
export interface ConnectionComponents {
|
|
14
|
+
peerStore: PeerStore
|
|
15
|
+
registrar: Registrar
|
|
16
|
+
metrics?: Metrics
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface ConnectionInit {
|
|
20
|
+
id: string
|
|
21
|
+
maConn: MultiaddrConnection
|
|
22
|
+
stream: MessageStream
|
|
23
|
+
remotePeer: PeerId
|
|
24
|
+
direction?: MessageStreamDirection
|
|
25
|
+
muxer?: StreamMuxer
|
|
26
|
+
cryptoProtocol?: string
|
|
27
|
+
limits?: ConnectionLimits
|
|
28
|
+
outboundStreamProtocolNegotiationTimeout?: number
|
|
29
|
+
inboundStreamProtocolNegotiationTimeout?: number
|
|
30
|
+
closeTimeout?: number
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* An implementation of the js-libp2p connection.
|
|
35
|
+
* Any libp2p transport should use an upgrader to return this connection.
|
|
36
|
+
*/
|
|
37
|
+
export class Connection extends TypedEventEmitter<MessageStreamEvents> implements ConnectionInterface {
|
|
38
|
+
public readonly id: string
|
|
39
|
+
public readonly remoteAddr: Multiaddr
|
|
40
|
+
public readonly remotePeer: PeerId
|
|
41
|
+
public direction: MessageStreamDirection
|
|
42
|
+
public timeline: MultiaddrConnectionTimeline
|
|
43
|
+
public direct: boolean
|
|
44
|
+
public multiplexer?: string
|
|
45
|
+
public encryption?: string
|
|
46
|
+
public limits?: ConnectionLimits
|
|
47
|
+
public readonly log: Logger
|
|
48
|
+
|
|
49
|
+
private readonly maConn: MultiaddrConnection
|
|
50
|
+
private readonly muxer?: StreamMuxer
|
|
51
|
+
private readonly components: ConnectionComponents
|
|
52
|
+
private readonly outboundStreamProtocolNegotiationTimeout: number
|
|
53
|
+
private readonly inboundStreamProtocolNegotiationTimeout: number
|
|
54
|
+
private readonly closeTimeout: number
|
|
55
|
+
|
|
56
|
+
constructor (components: ConnectionComponents, init: ConnectionInit) {
|
|
57
|
+
super()
|
|
58
|
+
|
|
59
|
+
this.components = components
|
|
60
|
+
|
|
61
|
+
this.id = init.id
|
|
62
|
+
this.remoteAddr = init.maConn.remoteAddr
|
|
63
|
+
this.remotePeer = init.remotePeer
|
|
64
|
+
this.direction = init.direction ?? 'outbound'
|
|
65
|
+
this.timeline = init.maConn.timeline
|
|
66
|
+
this.encryption = init.cryptoProtocol
|
|
67
|
+
this.limits = init.limits
|
|
68
|
+
this.maConn = init.maConn
|
|
69
|
+
this.log = init.maConn.log
|
|
70
|
+
this.outboundStreamProtocolNegotiationTimeout = init.outboundStreamProtocolNegotiationTimeout ?? PROTOCOL_NEGOTIATION_TIMEOUT
|
|
71
|
+
this.inboundStreamProtocolNegotiationTimeout = init.inboundStreamProtocolNegotiationTimeout ?? PROTOCOL_NEGOTIATION_TIMEOUT
|
|
72
|
+
this.closeTimeout = init.closeTimeout ?? CONNECTION_CLOSE_TIMEOUT
|
|
73
|
+
this.direct = isDirect(init.maConn.remoteAddr)
|
|
74
|
+
|
|
75
|
+
this.onIncomingStream = this.onIncomingStream.bind(this)
|
|
76
|
+
|
|
77
|
+
if (this.remoteAddr.getComponents().find(component => component.code === CODE_P2P) == null) {
|
|
78
|
+
this.remoteAddr = this.remoteAddr.encapsulate(`/p2p/${this.remotePeer}`)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (init.muxer != null) {
|
|
82
|
+
this.multiplexer = init.muxer.protocol
|
|
83
|
+
this.muxer = init.muxer
|
|
84
|
+
this.muxer.addEventListener('stream', this.onIncomingStream)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
this.maConn.addEventListener('close', (evt) => {
|
|
88
|
+
this.dispatchEvent(new StreamCloseEvent(evt.local, evt.error))
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
readonly [Symbol.toStringTag] = 'Connection'
|
|
93
|
+
|
|
94
|
+
readonly [connectionSymbol] = true
|
|
95
|
+
|
|
96
|
+
get streams (): Stream[] {
|
|
97
|
+
return this.muxer?.streams ?? []
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
get status (): ConnectionStatus {
|
|
101
|
+
return this.maConn.status
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Create a new stream over this connection
|
|
106
|
+
*/
|
|
107
|
+
newStream = async (protocols: string[], options: NewStreamOptions = {}): Promise<Stream> => {
|
|
108
|
+
if (this.muxer == null) {
|
|
109
|
+
throw new MuxerUnavailableError('Connection is not multiplexed')
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (this.muxer.status !== 'open') {
|
|
113
|
+
throw new ConnectionClosedError(`The connection muxer is "${this.muxer.status}" and not "open"`)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (this.maConn.status !== 'open') {
|
|
117
|
+
throw new ConnectionClosedError(`The connection is "${this.status}" and not "open"`)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (this.limits != null && options?.runOnLimitedConnection !== true) {
|
|
121
|
+
throw new LimitedConnectionError('Cannot open protocol stream on limited connection')
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (!Array.isArray(protocols)) {
|
|
125
|
+
protocols = [protocols]
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
this.log.trace('starting new stream for protocols %s', protocols)
|
|
129
|
+
const muxedStream = await this.muxer.createStream({
|
|
130
|
+
...options,
|
|
131
|
+
|
|
132
|
+
// most underlying transports only support negotiating a single protocol
|
|
133
|
+
// so only pass the early protocol if a single protocol has been requested
|
|
134
|
+
// otherwise fall back to mss
|
|
135
|
+
protocol: protocols.length === 1 ? protocols[0] : undefined
|
|
136
|
+
})
|
|
137
|
+
this.log.trace('started new stream %s for protocols %s', muxedStream.id, protocols)
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
if (options.signal == null) {
|
|
141
|
+
muxedStream.log('no abort signal was passed while trying to negotiate protocols %s falling back to default timeout', protocols)
|
|
142
|
+
|
|
143
|
+
const signal = AbortSignal.timeout(this.outboundStreamProtocolNegotiationTimeout)
|
|
144
|
+
setMaxListeners(Infinity, signal)
|
|
145
|
+
|
|
146
|
+
options = {
|
|
147
|
+
...options,
|
|
148
|
+
signal
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (muxedStream.protocol === '') {
|
|
153
|
+
muxedStream.log.trace('selecting protocol from protocols %s', protocols)
|
|
154
|
+
|
|
155
|
+
muxedStream.protocol = await mss.select(muxedStream, protocols, options)
|
|
156
|
+
|
|
157
|
+
muxedStream.log('negotiated protocol %s', muxedStream.protocol)
|
|
158
|
+
} else {
|
|
159
|
+
muxedStream.log('pre-negotiated protocol %s', muxedStream.protocol)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const outgoingLimit = findOutgoingStreamLimit(muxedStream.protocol, this.components.registrar, options)
|
|
163
|
+
const streamCount = countStreams(muxedStream.protocol, 'outbound', this)
|
|
164
|
+
|
|
165
|
+
if (streamCount > outgoingLimit) {
|
|
166
|
+
const err = new TooManyOutboundProtocolStreamsError(`Too many outbound protocol streams for protocol "${muxedStream.protocol}" - ${streamCount}/${outgoingLimit}`)
|
|
167
|
+
muxedStream.abort(err)
|
|
168
|
+
|
|
169
|
+
throw err
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// If a protocol stream has been successfully negotiated and is to be passed to the application,
|
|
173
|
+
// the peer store should ensure that the peer is registered with that protocol
|
|
174
|
+
await this.components.peerStore.merge(this.remotePeer, {
|
|
175
|
+
protocols: [muxedStream.protocol]
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
this.components.metrics?.trackProtocolStream(muxedStream)
|
|
179
|
+
|
|
180
|
+
return muxedStream
|
|
181
|
+
} catch (err: any) {
|
|
182
|
+
if (muxedStream.status === 'open') {
|
|
183
|
+
muxedStream.abort(err)
|
|
184
|
+
} else {
|
|
185
|
+
this.log.error('could not create new outbound stream on connection %s %a for protocols %s - %e', this.direction === 'inbound' ? 'from' : 'to', this.remoteAddr, protocols, err)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
throw err
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
private async onIncomingStream (evt: CustomEvent<Stream>): Promise<void> {
|
|
193
|
+
const muxedStream = evt.detail
|
|
194
|
+
|
|
195
|
+
const signal = AbortSignal.timeout(this.inboundStreamProtocolNegotiationTimeout)
|
|
196
|
+
setMaxListeners(Infinity, signal)
|
|
197
|
+
|
|
198
|
+
muxedStream.log('start protocol negotiation, timing out after %dms', this.inboundStreamProtocolNegotiationTimeout)
|
|
199
|
+
|
|
200
|
+
try {
|
|
201
|
+
if (muxedStream.protocol === '') {
|
|
202
|
+
const protocols = this.components.registrar.getProtocols()
|
|
203
|
+
|
|
204
|
+
muxedStream.log.trace('selecting protocol from protocols %s', protocols)
|
|
205
|
+
|
|
206
|
+
muxedStream.protocol = await mss.handle(muxedStream, protocols, {
|
|
207
|
+
signal
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
muxedStream.log('negotiated protocol %s', muxedStream.protocol)
|
|
211
|
+
} else {
|
|
212
|
+
muxedStream.log('pre-negotiated protocol %s', muxedStream.protocol)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const incomingLimit = findIncomingStreamLimit(muxedStream.protocol, this.components.registrar)
|
|
216
|
+
const streamCount = countStreams(muxedStream.protocol, 'inbound', this)
|
|
217
|
+
|
|
218
|
+
if (streamCount > incomingLimit) {
|
|
219
|
+
throw new TooManyInboundProtocolStreamsError(`Too many inbound protocol streams for protocol "${muxedStream.protocol}" - limit ${incomingLimit}`)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// If a protocol stream has been successfully negotiated and is to be passed to the application,
|
|
223
|
+
// the peer store should ensure that the peer is registered with that protocol
|
|
224
|
+
await this.components.peerStore.merge(this.remotePeer, {
|
|
225
|
+
protocols: [muxedStream.protocol]
|
|
226
|
+
}, {
|
|
227
|
+
signal
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
this.components.metrics?.trackProtocolStream(muxedStream)
|
|
231
|
+
|
|
232
|
+
const { handler, options } = this.components.registrar.getHandler(muxedStream.protocol)
|
|
233
|
+
|
|
234
|
+
if (this.limits != null && options.runOnLimitedConnection !== true) {
|
|
235
|
+
throw new LimitedConnectionError('Cannot open protocol stream on limited connection')
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
await handler(muxedStream, this)
|
|
239
|
+
} catch (err: any) {
|
|
240
|
+
muxedStream.abort(err)
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Close the connection
|
|
246
|
+
*/
|
|
247
|
+
async close (options: AbortOptions = {}): Promise<void> {
|
|
248
|
+
this.log('closing connection to %a', this.remoteAddr)
|
|
249
|
+
|
|
250
|
+
if (options.signal == null) {
|
|
251
|
+
const signal = AbortSignal.timeout(this.closeTimeout)
|
|
252
|
+
setMaxListeners(Infinity, signal)
|
|
253
|
+
|
|
254
|
+
options = {
|
|
255
|
+
...options,
|
|
256
|
+
signal
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
await this.muxer?.close(options)
|
|
261
|
+
await this.maConn.close(options)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
abort (err: Error): void {
|
|
265
|
+
this.muxer?.abort(err)
|
|
266
|
+
this.maConn.abort(err)
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export function createConnection (components: ConnectionComponents, init: ConnectionInit): ConnectionInterface {
|
|
271
|
+
return new Connection(components, init)
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function findIncomingStreamLimit (protocol: string, registrar: Registrar): number {
|
|
275
|
+
try {
|
|
276
|
+
const { options } = registrar.getHandler(protocol)
|
|
277
|
+
|
|
278
|
+
if (options.maxInboundStreams != null) {
|
|
279
|
+
return options.maxInboundStreams
|
|
280
|
+
}
|
|
281
|
+
} catch (err: any) {
|
|
282
|
+
if (err.name !== 'UnhandledProtocolError') {
|
|
283
|
+
throw err
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return DEFAULT_MAX_INBOUND_STREAMS
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function findOutgoingStreamLimit (protocol: string, registrar: Registrar, options: NewStreamOptions = {}): number {
|
|
291
|
+
try {
|
|
292
|
+
const { options } = registrar.getHandler(protocol)
|
|
293
|
+
|
|
294
|
+
if (options.maxOutboundStreams != null) {
|
|
295
|
+
return options.maxOutboundStreams
|
|
296
|
+
}
|
|
297
|
+
} catch (err: any) {
|
|
298
|
+
if (err.name !== 'UnhandledProtocolError') {
|
|
299
|
+
throw err
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return options.maxOutboundStreams ?? DEFAULT_MAX_OUTBOUND_STREAMS
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function countStreams (protocol: string, direction: 'inbound' | 'outbound', connection: Connection): number {
|
|
307
|
+
let streamCount = 0
|
|
308
|
+
|
|
309
|
+
connection.streams.forEach(stream => {
|
|
310
|
+
if (stream.direction === direction && stream.protocol === protocol) {
|
|
311
|
+
streamCount++
|
|
312
|
+
}
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
return streamCount
|
|
316
|
+
}
|
package/src/get-peer.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { InvalidMultiaddrError, InvalidParametersError, isPeerId } from '@libp2p/interface'
|
|
2
2
|
import { peerIdFromString } from '@libp2p/peer-id'
|
|
3
|
-
import { isMultiaddr } from '@multiformats/multiaddr'
|
|
3
|
+
import { CODE_P2P, isMultiaddr } from '@multiformats/multiaddr'
|
|
4
4
|
import { PEER_ID } from '@multiformats/multiaddr-matcher'
|
|
5
5
|
import type { PeerId } from '@libp2p/interface'
|
|
6
6
|
import type { Multiaddr } from '@multiformats/multiaddr'
|
|
@@ -24,7 +24,7 @@ export function getPeerAddress (peer: PeerId | Multiaddr | Multiaddr[]): PeerAdd
|
|
|
24
24
|
let peerId: PeerId | undefined
|
|
25
25
|
|
|
26
26
|
if (multiaddrs.length > 0) {
|
|
27
|
-
const peerIdStr = multiaddrs[0].
|
|
27
|
+
const peerIdStr = multiaddrs[0].getComponents().findLast(c => c.code === CODE_P2P)?.value
|
|
28
28
|
peerId = peerIdStr == null ? undefined : peerIdFromString(peerIdStr)
|
|
29
29
|
|
|
30
30
|
// ensure PeerId is either not set or is consistent
|
|
@@ -33,7 +33,7 @@ export function getPeerAddress (peer: PeerId | Multiaddr | Multiaddr[]): PeerAdd
|
|
|
33
33
|
throw new InvalidMultiaddrError('Invalid multiaddr')
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
const maPeerIdStr = ma.
|
|
36
|
+
const maPeerIdStr = ma.getComponents().findLast(c => c.code === CODE_P2P)?.value
|
|
37
37
|
|
|
38
38
|
if (maPeerIdStr == null) {
|
|
39
39
|
if (peerId != null) {
|
package/src/index.ts
CHANGED
|
@@ -184,8 +184,8 @@ export type Libp2pOptions<T extends ServiceMap = ServiceMap> = Libp2pInit<T> & {
|
|
|
184
184
|
* import { createLibp2p } from 'libp2p'
|
|
185
185
|
* import { tcp } from '@libp2p/tcp'
|
|
186
186
|
* import { mplex } from '@libp2p/mplex'
|
|
187
|
-
* import { noise } from '@
|
|
188
|
-
* import { yamux } from '@
|
|
187
|
+
* import { noise } from '@libp2p/noise'
|
|
188
|
+
* import { yamux } from '@libp2p/yamux'
|
|
189
189
|
*
|
|
190
190
|
* // specify options
|
|
191
191
|
* const options = {
|
package/src/libp2p.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { defaultLogger } from '@libp2p/logger'
|
|
|
4
4
|
import { PeerSet } from '@libp2p/peer-collections'
|
|
5
5
|
import { peerIdFromString } from '@libp2p/peer-id'
|
|
6
6
|
import { persistentPeerStore } from '@libp2p/peer-store'
|
|
7
|
-
import { isMultiaddr } from '@multiformats/multiaddr'
|
|
7
|
+
import { CODE_P2P, isMultiaddr } from '@multiformats/multiaddr'
|
|
8
8
|
import { MemoryDatastore } from 'datastore-core/memory'
|
|
9
9
|
import { TypedEventEmitter, setMaxListeners } from 'main-event'
|
|
10
10
|
import { concat as uint8ArrayConcat } from 'uint8arrays/concat'
|
|
@@ -120,7 +120,8 @@ export class Libp2p<T extends ServiceMap = ServiceMap> extends TypedEventEmitter
|
|
|
120
120
|
streamMuxers: (init.streamMuxers ?? []).map((fn, index) => this.configureComponent(`stream-muxers-${index}`, fn(this.components))),
|
|
121
121
|
inboundUpgradeTimeout: init.connectionManager?.inboundUpgradeTimeout,
|
|
122
122
|
inboundStreamProtocolNegotiationTimeout: init.connectionManager?.inboundStreamProtocolNegotiationTimeout ?? init.connectionManager?.protocolNegotiationTimeout,
|
|
123
|
-
outboundStreamProtocolNegotiationTimeout: init.connectionManager?.outboundStreamProtocolNegotiationTimeout ?? init.connectionManager?.protocolNegotiationTimeout
|
|
123
|
+
outboundStreamProtocolNegotiationTimeout: init.connectionManager?.outboundStreamProtocolNegotiationTimeout ?? init.connectionManager?.protocolNegotiationTimeout,
|
|
124
|
+
connectionCloseTimeout: init.connectionManager?.connectionCloseTimeout
|
|
124
125
|
})
|
|
125
126
|
|
|
126
127
|
// Setup the transport manager
|
|
@@ -304,9 +305,7 @@ export class Libp2p<T extends ServiceMap = ServiceMap> extends TypedEventEmitter
|
|
|
304
305
|
throw new InvalidParametersError('no protocols were provided to open a stream')
|
|
305
306
|
}
|
|
306
307
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
return connection.newStream(protocols, options)
|
|
308
|
+
return this.components.connectionManager.openStream(peer, protocols, options)
|
|
310
309
|
}
|
|
311
310
|
|
|
312
311
|
getMultiaddrs (): Multiaddr[] {
|
|
@@ -319,7 +318,7 @@ export class Libp2p<T extends ServiceMap = ServiceMap> extends TypedEventEmitter
|
|
|
319
318
|
|
|
320
319
|
async hangUp (peer: PeerId | Multiaddr, options: AbortOptions = {}): Promise<void> {
|
|
321
320
|
if (isMultiaddr(peer)) {
|
|
322
|
-
peer = peerIdFromString(peer.
|
|
321
|
+
peer = peerIdFromString(peer.getComponents().findLast(c => c.code === CODE_P2P)?.value ?? '')
|
|
323
322
|
}
|
|
324
323
|
|
|
325
324
|
await this.components.connectionManager.closeConnections(peer, options)
|
package/src/peer-routing.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NotFoundError } from '@libp2p/interface'
|
|
2
|
-
import { createScalableCuckooFilter } from '@libp2p/utils
|
|
2
|
+
import { createScalableCuckooFilter } from '@libp2p/utils'
|
|
3
3
|
import merge from 'it-merge'
|
|
4
4
|
import parallel from 'it-parallel'
|
|
5
5
|
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
|
package/src/random-walk.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { randomBytes } from '@libp2p/crypto'
|
|
|
2
2
|
import { anySignal } from 'any-signal'
|
|
3
3
|
import { TypedEventEmitter, setMaxListeners } from 'main-event'
|
|
4
4
|
import pDefer from 'p-defer'
|
|
5
|
-
import {
|
|
5
|
+
import { pEvent } from 'p-event'
|
|
6
6
|
import { raceSignal } from 'race-signal'
|
|
7
7
|
import type { AbortOptions, ComponentLogger, Logger, PeerInfo, PeerRouting, Startable } from '@libp2p/interface'
|
|
8
8
|
import type { RandomWalk as RandomWalkInterface } from '@libp2p/interface-internal'
|
|
@@ -68,12 +68,22 @@ export class RandomWalk extends TypedEventEmitter<RandomWalkEvents> implements R
|
|
|
68
68
|
this.needNext = pDefer()
|
|
69
69
|
|
|
70
70
|
// wait for a walk:peer or walk:error event
|
|
71
|
-
const event = await
|
|
72
|
-
|
|
71
|
+
const event = await pEvent<'walk:peer', CustomEvent<PeerInfo>>(this, 'walk:peer', {
|
|
72
|
+
signal,
|
|
73
|
+
rejectionEvents: [
|
|
74
|
+
'walk:error'
|
|
75
|
+
]
|
|
73
76
|
})
|
|
74
77
|
|
|
75
78
|
yield event.detail
|
|
76
79
|
}
|
|
80
|
+
} catch (err: any) {
|
|
81
|
+
// test for walk:error event
|
|
82
|
+
if (err.detail != null) {
|
|
83
|
+
throw err.detail
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
throw err
|
|
77
87
|
} finally {
|
|
78
88
|
signal.clear()
|
|
79
89
|
this.walkers--
|