1
1
import { logger } from '@libp2p/logger'
2
2
import { PeerMap , PeerSet } from '@libp2p/peer-collections'
3
3
import PQueue from 'p-queue'
4
- import { AUTO_DIAL_CONCURRENCY , AUTO_DIAL_INTERVAL , AUTO_DIAL_PRIORITY , MIN_CONNECTIONS } from './constants.js'
4
+ import { AUTO_DIAL_CONCURRENCY , AUTO_DIAL_INTERVAL , AUTO_DIAL_MAX_QUEUE_LENGTH , AUTO_DIAL_PRIORITY , MIN_CONNECTIONS } from './constants.js'
5
5
import type { ConnectionManager } from '@libp2p/interface-connection-manager'
6
6
import type { Libp2pEvents } from '@libp2p/interface-libp2p'
7
7
import type { PeerStore } from '@libp2p/interface-peer-store'
@@ -12,6 +12,7 @@ const log = logger('libp2p:connection-manager:auto-dial')
12
12
13
13
interface AutoDialInit {
14
14
minConnections ?: number
15
+ maxQueueLength ?: number
15
16
autoDialConcurrency ?: number
16
17
autoDialPriority ?: number
17
18
autoDialInterval ?: number
@@ -25,6 +26,7 @@ interface AutoDialComponents {
25
26
26
27
const defaultOptions = {
27
28
minConnections : MIN_CONNECTIONS ,
29
+ maxQueueLength : AUTO_DIAL_MAX_QUEUE_LENGTH ,
28
30
autoDialConcurrency : AUTO_DIAL_CONCURRENCY ,
29
31
autoDialPriority : AUTO_DIAL_PRIORITY ,
30
32
autoDialInterval : AUTO_DIAL_INTERVAL
@@ -37,8 +39,10 @@ export class AutoDial implements Startable {
37
39
private readonly minConnections : number
38
40
private readonly autoDialPriority : number
39
41
private readonly autoDialIntervalMs : number
42
+ private readonly autoDialMaxQueueLength : number
40
43
private autoDialInterval ?: ReturnType < typeof setInterval >
41
44
private started : boolean
45
+ private running : boolean
42
46
43
47
/**
44
48
* Proactively tries to connect to known peers stored in the PeerStore.
@@ -51,7 +55,9 @@ export class AutoDial implements Startable {
51
55
this . minConnections = init . minConnections ?? defaultOptions . minConnections
52
56
this . autoDialPriority = init . autoDialPriority ?? defaultOptions . autoDialPriority
53
57
this . autoDialIntervalMs = init . autoDialInterval ?? defaultOptions . autoDialInterval
58
+ this . autoDialMaxQueueLength = init . maxQueueLength ?? defaultOptions . maxQueueLength
54
59
this . started = false
60
+ this . running = false
55
61
this . queue = new PQueue ( {
56
62
concurrency : init . autoDialConcurrency ?? defaultOptions . autoDialConcurrency
57
63
} )
@@ -73,7 +79,7 @@ export class AutoDial implements Startable {
73
79
}
74
80
75
81
start ( ) : void {
76
- this . autoDialInterval = setInterval ( ( ) => {
82
+ this . autoDialInterval = setTimeout ( ( ) => {
77
83
this . autoDial ( )
78
84
. catch ( err => {
79
85
log . error ( 'error while autodialing' , err )
@@ -92,8 +98,9 @@ export class AutoDial implements Startable {
92
98
stop ( ) : void {
93
99
// clear the queue
94
100
this . queue . clear ( )
95
- clearInterval ( this . autoDialInterval )
101
+ clearTimeout ( this . autoDialInterval )
96
102
this . started = false
103
+ this . running = false
97
104
}
98
105
99
106
async autoDial ( ) : Promise < void > {
@@ -103,47 +110,62 @@ export class AutoDial implements Startable {
103
110
104
111
const connections = this . connectionManager . getConnectionsMap ( )
105
112
const numConnections = connections . size
106
- const dialQueue = new PeerSet (
107
- // @ts -expect-error boolean filter removes falsy peer IDs
108
- this . connectionManager . getDialQueue ( )
109
- . map ( queue => queue . peerId )
110
- . filter ( Boolean )
111
- )
112
113
113
114
// Already has enough connections
114
115
if ( numConnections >= this . minConnections ) {
115
116
log . trace ( 'have enough connections %d/%d' , numConnections , this . minConnections )
116
117
return
117
118
}
118
119
119
- log ( 'not enough connections %d/%d - will dial peers to increase the number of connections' , numConnections , this . minConnections )
120
+ if ( this . queue . size > this . autoDialMaxQueueLength ) {
121
+ log ( 'not enough connections %d/%d but auto dial queue is full' , numConnections , this . minConnections )
122
+ return
123
+ }
120
124
121
- // Sort peers on whether we know protocols or public keys for them
122
- const peers = await this . peerStore . all ( )
125
+ if ( this . running ) {
126
+ log ( 'not enough connections %d/%d - but skipping autodial as it is already running' , numConnections , this . minConnections )
127
+ return
128
+ }
123
129
124
- // Remove some peers
125
- const filteredPeers = peers . filter ( ( peer ) => {
126
- // Remove peers without addresses
127
- if ( peer . addresses . length === 0 ) {
128
- return false
129
- }
130
+ this . running = true
130
131
131
- // remove peers we are already connected to
132
- if ( connections . has ( peer . id ) ) {
133
- return false
134
- }
132
+ log ( 'not enough connections %d/%d - will dial peers to increase the number of connections' , numConnections , this . minConnections )
135
133
136
- // remove peers we are already dialling
137
- if ( dialQueue . has ( peer . id ) ) {
138
- return false
139
- }
134
+ const dialQueue = new PeerSet (
135
+ // @ts -expect-error boolean filter removes falsy peer IDs
136
+ this . connectionManager . getDialQueue ( )
137
+ . map ( queue => queue . peerId )
138
+ . filter ( Boolean )
139
+ )
140
140
141
- return true
141
+ // Sort peers on whether we know protocols or public keys for them
142
+ const peers = await this . peerStore . all ( {
143
+ filters : [
144
+ // Remove some peers
145
+ ( peer ) => {
146
+ // Remove peers without addresses
147
+ if ( peer . addresses . length === 0 ) {
148
+ return false
149
+ }
150
+
151
+ // remove peers we are already connected to
152
+ if ( connections . has ( peer . id ) ) {
153
+ return false
154
+ }
155
+
156
+ // remove peers we are already dialling
157
+ if ( dialQueue . has ( peer . id ) ) {
158
+ return false
159
+ }
160
+
161
+ return true
162
+ }
163
+ ]
142
164
} )
143
165
144
166
// shuffle the peers - this is so peers with the same tag values will be
145
167
// dialled in a different order each time
146
- const shuffledPeers = filteredPeers . sort ( ( ) => Math . random ( ) > 0.5 ? 1 : - 1 )
168
+ const shuffledPeers = peers . sort ( ( ) => Math . random ( ) > 0.5 ? 1 : - 1 )
147
169
148
170
// Sort shuffled peers by tag value
149
171
const peerValues = new PeerMap < number > ( )
@@ -196,5 +218,16 @@ export class AutoDial implements Startable {
196
218
log . error ( 'could not connect to peerStore stored peer' , err )
197
219
} )
198
220
}
221
+
222
+ this . running = false
223
+
224
+ if ( this . started ) {
225
+ this . autoDialInterval = setTimeout ( ( ) => {
226
+ this . autoDial ( )
227
+ . catch ( err => {
228
+ log . error ( 'error while autodialing' , err )
229
+ } )
230
+ } , this . autoDialIntervalMs )
231
+ }
199
232
}
200
233
}
0 commit comments