@@ -27,13 +27,15 @@ class Dialer {
27
27
* @param {number } [options.concurrency = MAX_PARALLEL_DIALS] - Number of max concurrent dials.
28
28
* @param {number } [options.perPeerLimit = MAX_PER_PEER_DIALS] - Number of max concurrent dials per peer.
29
29
* @param {number } [options.timeout = DIAL_TIMEOUT] - How long a dial attempt is allowed to take.
30
+ * @param {object } [options.resolvers = {}] - multiaddr resolvers to use when dialing
30
31
*/
31
32
constructor ( {
32
33
transportManager,
33
34
peerStore,
34
35
concurrency = MAX_PARALLEL_DIALS ,
35
36
timeout = DIAL_TIMEOUT ,
36
- perPeerLimit = MAX_PER_PEER_DIALS
37
+ perPeerLimit = MAX_PER_PEER_DIALS ,
38
+ resolvers = { }
37
39
} ) {
38
40
this . transportManager = transportManager
39
41
this . peerStore = peerStore
@@ -42,6 +44,10 @@ class Dialer {
42
44
this . perPeerLimit = perPeerLimit
43
45
this . tokens = [ ...new Array ( concurrency ) ] . map ( ( _ , index ) => index )
44
46
this . _pendingDials = new Map ( )
47
+
48
+ for ( const [ key , value ] of Object . entries ( resolvers ) ) {
49
+ multiaddr . resolvers . set ( key , value )
50
+ }
45
51
}
46
52
47
53
/**
@@ -69,7 +75,7 @@ class Dialer {
69
75
* @returns {Promise<Connection> }
70
76
*/
71
77
async connectToPeer ( peer , options = { } ) {
72
- const dialTarget = this . _createDialTarget ( peer )
78
+ const dialTarget = await this . _createDialTarget ( peer )
73
79
74
80
if ( ! dialTarget . addrs . length ) {
75
81
throw errCode ( new Error ( 'The dial request has no addresses' ) , codes . ERR_NO_VALID_ADDRESSES )
@@ -105,22 +111,28 @@ class Dialer {
105
111
*
106
112
* @private
107
113
* @param {PeerId|Multiaddr|string } peer - A PeerId or Multiaddr
108
- * @returns {DialTarget }
114
+ * @returns {Promise< DialTarget> }
109
115
*/
110
- _createDialTarget ( peer ) {
116
+ async _createDialTarget ( peer ) {
111
117
const { id, multiaddrs } = getPeer ( peer )
112
118
113
119
if ( multiaddrs ) {
114
120
this . peerStore . addressBook . add ( id , multiaddrs )
115
121
}
116
122
117
- let addrs = this . peerStore . addressBook . getMultiaddrsForPeer ( id ) || [ ]
123
+ let knownAddrs = this . peerStore . addressBook . getMultiaddrsForPeer ( id ) || [ ]
118
124
119
125
// If received a multiaddr to dial, it should be the first to use
120
126
// But, if we know other multiaddrs for the peer, we should try them too.
121
127
if ( multiaddr . isMultiaddr ( peer ) ) {
122
- addrs = addrs . filter ( ( addr ) => ! peer . equals ( addr ) )
123
- addrs . unshift ( peer )
128
+ knownAddrs = knownAddrs . filter ( ( addr ) => ! peer . equals ( addr ) )
129
+ knownAddrs . unshift ( peer )
130
+ }
131
+
132
+ const addrs = [ ]
133
+ for ( const a of knownAddrs ) {
134
+ const resolvedAddrs = await this . _resolve ( a )
135
+ resolvedAddrs . forEach ( ra => addrs . push ( ra ) )
124
136
}
125
137
126
138
return {
@@ -190,6 +202,52 @@ class Dialer {
190
202
log ( 'token %d released' , token )
191
203
this . tokens . push ( token )
192
204
}
205
+
206
+ /**
207
+ * Resolve multiaddr recursively.
208
+ *
209
+ * @param {Multiaddr } ma
210
+ * @returns {Promise<Array<Multiaddr>> }
211
+ */
212
+ async _resolve ( ma ) {
213
+ // TODO: recursive logic should live in multiaddr once dns4/dns6 support is in place
214
+ // Now only supporting resolve for dnsaddr
215
+ const resolvableProto = ma . protoNames ( ) . includes ( 'dnsaddr' )
216
+
217
+ // Multiaddr is not resolvable? End recursion!
218
+ if ( ! resolvableProto ) {
219
+ return [ ma ]
220
+ }
221
+
222
+ const resolvedMultiaddrs = await this . _resolveRecord ( ma )
223
+ const recursiveMultiaddrs = await Promise . all ( resolvedMultiaddrs . map ( ( nm ) => {
224
+ return this . _resolve ( nm )
225
+ } ) )
226
+
227
+ return recursiveMultiaddrs . flat ( ) . reduce ( ( array , newM ) => {
228
+ if ( ! array . find ( m => m . equals ( newM ) ) ) {
229
+ array . push ( newM )
230
+ }
231
+ return array
232
+ } , [ ] ) // Unique addresses
233
+ }
234
+
235
+ /**
236
+ * Resolve a given multiaddr. If this fails, an empty array will be returned
237
+ *
238
+ * @param {Multiaddr } ma
239
+ * @returns {Promise<Array<Multiaddr>> }
240
+ */
241
+ async _resolveRecord ( ma ) {
242
+ try {
243
+ ma = multiaddr ( ma . toString ( ) ) // Use current multiaddr module
244
+ const multiaddrs = await ma . resolve ( )
245
+ return multiaddrs
246
+ } catch ( _ ) {
247
+ log . error ( `multiaddr ${ ma } could not be resolved` )
248
+ return [ ]
249
+ }
250
+ }
193
251
}
194
252
195
253
module . exports = Dialer
0 commit comments