11import { NotFoundError , contentRoutingSymbol , peerRoutingSymbol , setMaxListeners } from '@libp2p/interface'
2- import { logger } from '@libp2p/logger'
32import { peerIdFromString } from '@libp2p/peer-id'
43import { multiaddr } from '@multiformats/multiaddr'
54import { anySignal } from 'any-signal'
@@ -11,26 +10,24 @@ import defer from 'p-defer'
1110import PQueue from 'p-queue'
1211import { BadResponseError , InvalidRequestError } from './errors.js'
1312import { DelegatedRoutingV1HttpApiClientContentRouting , DelegatedRoutingV1HttpApiClientPeerRouting } from './routings.js'
14- import type { DelegatedRoutingV1HttpApiClient , DelegatedRoutingV1HttpApiClientInit , GetProvidersOptions , GetPeersOptions , GetIPNSOptions , PeerRecord } from './index.js'
15- import type { ContentRouting , PeerRouting , AbortOptions , PeerId } from '@libp2p/interface'
13+ import type { DelegatedRoutingV1HttpApiClient as DelegatedRoutingV1HttpApiClientInterface , DelegatedRoutingV1HttpApiClientInit , GetProvidersOptions , GetPeersOptions , GetIPNSOptions , PeerRecord , DelegatedRoutingV1HttpApiClientComponents } from './index.js'
14+ import type { ContentRouting , PeerRouting , AbortOptions , PeerId , Logger } from '@libp2p/interface'
1615import type { Multiaddr } from '@multiformats/multiaddr'
1716import type { IPNSRecord } from 'ipns'
1817import type { CID } from 'multiformats'
1918
20- const log = logger ( 'delegated-routing-v1-http-api-client' )
21-
2219const defaultValues = {
2320 concurrentRequests : 4 ,
2421 timeout : 30e3 ,
2522 cacheTTL : 5 * 60 * 1000 , // 5 minutes default as per https://specs.ipfs.tech/routing/http-routing-v1/#response-headers
2623 cacheName : 'delegated-routing-v1-cache'
2724}
2825
29- export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV1HttpApiClient {
26+ export class DelegatedRoutingV1HttpApiClient implements DelegatedRoutingV1HttpApiClientInterface {
27+ public readonly url : URL
3028 private started : boolean
3129 private readonly httpQueue : PQueue
3230 private readonly shutDownController : AbortController
33- private readonly clientUrl : URL
3431 private readonly timeout : number
3532 private readonly contentRouting : ContentRouting
3633 private readonly peerRouting : PeerRouting
@@ -40,18 +37,21 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
4037 private readonly cacheName : string
4138 private cache ?: Cache
4239 private readonly cacheTTL : number
40+ private log : Logger
41+
4342 /**
4443 * Create a new DelegatedContentRouting instance
4544 */
46- constructor ( url : string | URL , init : DelegatedRoutingV1HttpApiClientInit = { } ) {
45+ constructor ( components : DelegatedRoutingV1HttpApiClientComponents , init : DelegatedRoutingV1HttpApiClientInit & { url : string | URL } ) {
46+ this . log = components . logger . forComponent ( 'delegated-routing-v1-http-api-client' )
4747 this . started = false
4848 this . shutDownController = new AbortController ( )
4949 setMaxListeners ( Infinity , this . shutDownController . signal )
5050 this . httpQueue = new PQueue ( {
5151 concurrency : init . concurrentRequests ?? defaultValues . concurrentRequests
5252 } )
5353 this . inFlightRequests = new Map ( ) // Tracks in-flight requests to avoid duplicate requests
54- this . clientUrl = url instanceof URL ? url : new URL ( url )
54+ this . url = init . url instanceof URL ? init . url : new URL ( init . url )
5555 this . timeout = init . timeout ?? defaultValues . timeout
5656 this . filterAddrs = init . filterAddrs
5757 this . filterProtocols = init . filterProtocols
@@ -85,7 +85,7 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
8585 this . cache = await globalThis . caches ?. open ( this . cacheName )
8686
8787 if ( this . cache != null ) {
88- log ( 'cache enabled with ttl %d' , this . cacheTTL )
88+ this . log ( 'cache enabled with ttl %d' , this . cacheTTL )
8989 }
9090 }
9191 }
@@ -101,7 +101,7 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
101101 }
102102
103103 async * getProviders ( cid : CID , options : GetProvidersOptions = { } ) : AsyncGenerator < PeerRecord > {
104- log ( 'getProviders starts: %c' , cid )
104+ this . log ( 'getProviders starts: %c' , cid )
105105
106106 const timeoutSignal = AbortSignal . timeout ( this . timeout )
107107 const signal = anySignal ( [ this . shutDownController . signal , timeoutSignal , options . signal ] )
@@ -118,7 +118,7 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
118118 await onStart . promise
119119
120120 // https://specs.ipfs.tech/routing/http-routing-v1/
121- const url = new URL ( `${ this . clientUrl } routing/v1/providers/${ cid } ` )
121+ const url = new URL ( `${ this . url } routing/v1/providers/${ cid } ` )
122122
123123 this . #addFilterParams( url , options . filterAddrs , options . filterProtocols )
124124 const getOptions = { headers : { Accept : 'application/x-ndjson' } , signal }
@@ -175,12 +175,12 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
175175 } finally {
176176 signal . clear ( )
177177 onFinish . resolve ( )
178- log ( 'getProviders finished: %c' , cid )
178+ this . log ( 'getProviders finished: %c' , cid )
179179 }
180180 }
181181
182182 async * getPeers ( peerId : PeerId , options : GetPeersOptions = { } ) : AsyncGenerator < PeerRecord > {
183- log ( 'getPeers starts: %c' , peerId )
183+ this . log ( 'getPeers starts: %c' , peerId )
184184
185185 const timeoutSignal = AbortSignal . timeout ( this . timeout )
186186 const signal = anySignal ( [ this . shutDownController . signal , timeoutSignal , options . signal ] )
@@ -197,7 +197,7 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
197197 await onStart . promise
198198
199199 // https://specs.ipfs.tech/routing/http-routing-v1/
200- const url = new URL ( `${ this . clientUrl } routing/v1/peers/${ peerId . toCID ( ) . toString ( ) } ` )
200+ const url = new URL ( `${ this . url } routing/v1/peers/${ peerId . toCID ( ) . toString ( ) } ` )
201201 this . #addFilterParams( url , options . filterAddrs , options . filterProtocols )
202202
203203 const getOptions = { headers : { Accept : 'application/x-ndjson' } , signal }
@@ -241,16 +241,16 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
241241 }
242242 }
243243 } catch ( err ) {
244- log . error ( 'getPeers errored: ' , err )
244+ this . log . error ( 'getPeers errored - %e ' , err )
245245 } finally {
246246 signal . clear ( )
247247 onFinish . resolve ( )
248- log ( 'getPeers finished: %c' , peerId )
248+ this . log ( 'getPeers finished: %c' , peerId )
249249 }
250250 }
251251
252252 async getIPNS ( libp2pKey : CID < unknown , 0x72 , 0x00 | 0x12 , 1 > , options : GetIPNSOptions = { } ) : Promise < IPNSRecord > {
253- log ( 'getIPNS starts: %s' , libp2pKey )
253+ this . log ( 'getIPNS starts: %s' , libp2pKey )
254254
255255 const timeoutSignal = AbortSignal . timeout ( this . timeout )
256256 const signal = anySignal ( [ this . shutDownController . signal , timeoutSignal , options . signal ] )
@@ -264,15 +264,15 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
264264 } )
265265
266266 // https://specs.ipfs.tech/routing/http-routing-v1/
267- const resource = `${ this . clientUrl } routing/v1/ipns/${ libp2pKey } `
267+ const resource = `${ this . url } routing/v1/ipns/${ libp2pKey } `
268268
269269 try {
270270 await onStart . promise
271271
272272 const getOptions = { headers : { Accept : 'application/vnd.ipfs.ipns-record' } , signal }
273273 const res = await this . #makeRequest( resource , getOptions )
274274
275- log ( 'getIPNS GET %s %d' , resource , res . status )
275+ this . log ( 'getIPNS GET %s %d' , resource , res . status )
276276
277277 // Per IPIP-0513: Handle 404 as "no record found" for backward compatibility
278278 // IPNS is different - we still throw NotFoundError for 404 (backward compat)
@@ -311,18 +311,18 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
311311
312312 return unmarshalIPNSRecord ( body )
313313 } catch ( err : any ) {
314- log . error ( 'getIPNS GET %s error: ' , resource , err )
314+ this . log . error ( 'getIPNS GET %s error - %e ' , resource , err )
315315
316316 throw err
317317 } finally {
318318 signal . clear ( )
319319 onFinish . resolve ( )
320- log ( 'getIPNS finished: %s' , libp2pKey )
320+ this . log ( 'getIPNS finished: %s' , libp2pKey )
321321 }
322322 }
323323
324324 async putIPNS ( libp2pKey : CID < unknown , 0x72 , 0x00 | 0x12 , 1 > , record : IPNSRecord , options : AbortOptions = { } ) : Promise < void > {
325- log ( 'putIPNS starts: %c' , libp2pKey )
325+ this . log ( 'putIPNS starts: %c' , libp2pKey )
326326
327327 const timeoutSignal = AbortSignal . timeout ( this . timeout )
328328 const signal = anySignal ( [ this . shutDownController . signal , timeoutSignal , options . signal ] )
@@ -336,7 +336,7 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
336336 } )
337337
338338 // https://specs.ipfs.tech/routing/http-routing-v1/
339- const resource = `${ this . clientUrl } routing/v1/ipns/${ libp2pKey } `
339+ const resource = `${ this . url } routing/v1/ipns/${ libp2pKey } `
340340
341341 try {
342342 await onStart . promise
@@ -346,19 +346,19 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
346346 const getOptions = { method : 'PUT' , headers : { 'Content-Type' : 'application/vnd.ipfs.ipns-record' } , body, signal }
347347 const res = await this . #makeRequest( resource , getOptions )
348348
349- log ( 'putIPNS PUT %s %d' , resource , res . status )
349+ this . log ( 'putIPNS PUT %s %d' , resource , res . status )
350350
351351 if ( res . status !== 200 ) {
352352 throw new BadResponseError ( 'PUT ipns response had status other than 200' )
353353 }
354354 } catch ( err : any ) {
355- log . error ( 'putIPNS PUT %s error: ' , resource , err . stack )
355+ this . log . error ( 'putIPNS PUT %s error - %e ' , resource , err . stack )
356356
357357 throw err
358358 } finally {
359359 signal . clear ( )
360360 onFinish . resolve ( )
361- log ( 'putIPNS finished: %c' , libp2pKey )
361+ this . log ( 'putIPNS finished: %c' , libp2pKey )
362362 }
363363 }
364364
@@ -384,7 +384,7 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
384384 Protocols : protocols
385385 }
386386 } catch ( err ) {
387- log . error ( 'could not conform record to peer schema' , err )
387+ this . log . error ( 'could not conform record to peer schema - %e ' , err )
388388 }
389389 }
390390
@@ -420,7 +420,7 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
420420 // Check if the cached response has expired
421421 const expires = parseInt ( cachedResponse . headers . get ( 'x-cache-expires' ) ?? '0' , 10 )
422422 if ( expires > Date . now ( ) ) {
423- log ( 'returning cached response for %s' , key )
423+ this . log ( 'returning cached response for %s' , key )
424424 return cachedResponse
425425 } else {
426426 // Remove expired response from cache
@@ -433,7 +433,7 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
433433 const existingRequest = this . inFlightRequests . get ( key )
434434 if ( existingRequest != null ) {
435435 const response = await existingRequest
436- log ( 'deduplicating outgoing request for %s' , key )
436+ this . log ( 'deduplicating outgoing request for %s' , key )
437437 return response . clone ( )
438438 }
439439
@@ -464,4 +464,8 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
464464 const response = await requestPromise
465465 return response
466466 }
467+
468+ toString ( ) : string {
469+ return `DefaultDelegatedRoutingV1HttpApiClient(${ this . url } )`
470+ }
467471}
0 commit comments