@@ -16,22 +16,20 @@ import (
1616 ipns "github.com/ipfs/boxo/ipns"
1717 "github.com/ipfs/boxo/routing/http/contentrouter"
1818 "github.com/ipfs/boxo/routing/http/internal/drjson"
19- "github.com/ipfs/boxo/routing/http/server"
2019 "github.com/ipfs/boxo/routing/http/types"
2120 "github.com/ipfs/boxo/routing/http/types/iter"
2221 jsontypes "github.com/ipfs/boxo/routing/http/types/json"
2322 "github.com/ipfs/boxo/routing/http/types/ndjson"
2423 "github.com/ipfs/go-cid"
2524 logging "github.com/ipfs/go-log/v2"
26- record "github.com/libp2p/go-libp2p-record"
2725 "github.com/libp2p/go-libp2p/core/crypto"
2826 "github.com/libp2p/go-libp2p/core/peer"
2927 "github.com/multiformats/go-multiaddr"
3028)
3129
3230var (
3331 _ contentrouter.Client = & client {}
34- logger = logging .Logger ("service/delegatedrouting " )
32+ logger = logging .Logger ("routing/http/client " )
3533 defaultHTTPClient = & http.Client {
3634 Transport : & ResponseBodyLimitedTransport {
3735 RoundTripper : http .DefaultTransport ,
@@ -50,18 +48,17 @@ const (
5048type client struct {
5149 baseURL string
5250 httpClient httpClient
53- validator record.Validator
5451 clock clock.Clock
55-
56- accepts string
52+ accepts string
5753
5854 peerID peer.ID
5955 addrs []types.Multiaddr
6056 identity crypto.PrivKey
6157
62- // called immeidately after signing a provide req
63- // used for testing, e.g. testing the server with a mangled signature
64- afterSignCallback func (req * types.WriteBitswapProviderRecord )
58+ // Called immediately after signing a provide request. It is used
59+ // for testing, e.g., testing the server with a mangled signature.
60+ //lint:ignore SA1019 // ignore staticcheck
61+ afterSignCallback func (req * types.WriteBitswapRecord )
6562}
6663
6764// defaultUserAgent is used as a fallback to inform HTTP server which library
@@ -121,12 +118,11 @@ func WithStreamResultsRequired() Option {
121118}
122119
123120// New creates a content routing API client.
124- // The Provider and identity parameters are option. If they are nil, the `Provide` method will not function.
121+ // The Provider and identity parameters are option. If they are nil, the [client.ProvideBitswap] method will not function.
125122func New (baseURL string , opts ... Option ) (* client , error ) {
126123 client := & client {
127124 baseURL : baseURL ,
128125 httpClient : defaultHTTPClient ,
129- validator : ipns.Validator {},
130126 clock : clock .New (),
131127 accepts : strings .Join ([]string {mediaTypeNDJSON , mediaTypeJSON }, "," ),
132128 }
@@ -164,11 +160,11 @@ func (c *measuringIter[T]) Close() error {
164160 return c .Iter .Close ()
165161}
166162
167- func (c * client ) FindProviders (ctx context.Context , key cid.Cid ) (provs iter.ResultIter [types.ProviderResponse ], err error ) {
163+ func (c * client ) FindProviders (ctx context.Context , key cid.Cid ) (providers iter.ResultIter [types.Record ], err error ) {
168164 // TODO test measurements
169165 m := newMeasurement ("FindProviders" )
170166
171- url := c .baseURL + server . ProvidePath + key .String ()
167+ url := c .baseURL + "/routing/v1/providers/" + key .String ()
172168 req , err := http .NewRequestWithContext (ctx , http .MethodGet , url , nil )
173169 if err != nil {
174170 return nil , err
@@ -192,7 +188,7 @@ func (c *client) FindProviders(ctx context.Context, key cid.Cid) (provs iter.Res
192188 if resp .StatusCode == http .StatusNotFound {
193189 resp .Body .Close ()
194190 m .record (ctx )
195- return iter.FromSlice [iter.Result [types.ProviderResponse ]](nil ), nil
191+ return iter.FromSlice [iter.Result [types.Record ]](nil ), nil
196192 }
197193
198194 if resp .StatusCode != http .StatusOK {
@@ -220,24 +216,27 @@ func (c *client) FindProviders(ctx context.Context, key cid.Cid) (provs iter.Res
220216 }
221217 }()
222218
223- var it iter.ResultIter [types.ProviderResponse ]
219+ var it iter.ResultIter [types.Record ]
224220 switch mediaType {
225221 case mediaTypeJSON :
226- parsedResp := & jsontypes.ReadProvidersResponse {}
222+ parsedResp := & jsontypes.ProvidersResponse {}
227223 err = json .NewDecoder (resp .Body ).Decode (parsedResp )
228- var sliceIt iter.Iter [types.ProviderResponse ] = iter .FromSlice (parsedResp .Providers )
224+ var sliceIt iter.Iter [types.Record ] = iter .FromSlice (parsedResp .Providers )
229225 it = iter .ToResultIter (sliceIt )
230226 case mediaTypeNDJSON :
231227 skipBodyClose = true
232- it = ndjson .NewReadProvidersResponseIter (resp .Body )
228+ it = ndjson .NewRecordsIter (resp .Body )
233229 default :
234230 logger .Errorw ("unknown media type" , "MediaType" , mediaType , "ContentType" , respContentType )
235231 return nil , errors .New ("unknown content type" )
236232 }
237233
238- return & measuringIter [iter.Result [types.ProviderResponse ]]{Iter : it , ctx : ctx , m : m }, nil
234+ return & measuringIter [iter.Result [types.Record ]]{Iter : it , ctx : ctx , m : m }, nil
239235}
240236
237+ // Deprecated: protocol-agnostic provide is being worked on in [IPIP-378]:
238+ //
239+ // [IPIP-378]: https://github.com/ipfs/specs/pull/378
241240func (c * client ) ProvideBitswap (ctx context.Context , keys []cid.Cid , ttl time.Duration ) (time.Duration , error ) {
242241 if c .identity == nil {
243242 return 0 , errors .New ("cannot provide Bitswap records without an identity" )
@@ -253,7 +252,7 @@ func (c *client) ProvideBitswap(ctx context.Context, keys []cid.Cid, ttl time.Du
253252
254253 now := c .clock .Now ()
255254
256- req := types.WriteBitswapProviderRecord {
255+ req := types.WriteBitswapRecord {
257256 Protocol : "transport-bitswap" ,
258257 Schema : types .SchemaBitswap ,
259258 Payload : types.BitswapPayload {
@@ -282,10 +281,13 @@ func (c *client) ProvideBitswap(ctx context.Context, keys []cid.Cid, ttl time.Du
282281}
283282
284283// ProvideAsync makes a provide request to a delegated router
285- func (c * client ) provideSignedBitswapRecord (ctx context.Context , bswp * types.WriteBitswapProviderRecord ) (time.Duration , error ) {
286- req := jsontypes.WriteProvidersRequest {Providers : []types.WriteProviderRecord {bswp }}
284+ //
285+ //lint:ignore SA1019 // ignore staticcheck
286+ func (c * client ) provideSignedBitswapRecord (ctx context.Context , bswp * types.WriteBitswapRecord ) (time.Duration , error ) {
287+ //lint:ignore SA1019 // ignore staticcheck
288+ req := jsontypes.WriteProvidersRequest {Providers : []types.Record {bswp }}
287289
288- url := c .baseURL + server . ProvidePath
290+ url := c .baseURL + "/routing/v1/providers/"
289291
290292 b , err := drjson .MarshalJSONBytes (req )
291293 if err != nil {
@@ -306,6 +308,8 @@ func (c *client) provideSignedBitswapRecord(ctx context.Context, bswp *types.Wri
306308 if resp .StatusCode != http .StatusOK {
307309 return 0 , httpError (resp .StatusCode , resp .Body )
308310 }
311+
312+ //lint:ignore SA1019 // ignore staticcheck
309313 var provideResult jsontypes.WriteProvidersResponse
310314 err = json .NewDecoder (resp .Body ).Decode (& provideResult )
311315 if err != nil {
@@ -315,7 +319,8 @@ func (c *client) provideSignedBitswapRecord(ctx context.Context, bswp *types.Wri
315319 return 0 , fmt .Errorf ("expected 1 result but got %d" , len (provideResult .ProvideResults ))
316320 }
317321
318- v , ok := provideResult .ProvideResults [0 ].(* types.WriteBitswapProviderRecordResponse )
322+ //lint:ignore SA1019 // ignore staticcheck
323+ v , ok := provideResult .ProvideResults [0 ].(* types.WriteBitswapRecordResponse )
319324 if ! ok {
320325 return 0 , fmt .Errorf ("expected AdvisoryTTL field" )
321326 }
@@ -327,7 +332,80 @@ func (c *client) provideSignedBitswapRecord(ctx context.Context, bswp *types.Wri
327332 return 0 , nil
328333}
329334
330- func (c * client ) FindIPNSRecord (ctx context.Context , name ipns.Name ) (* ipns.Record , error ) {
335+ func (c * client ) FindPeers (ctx context.Context , pid peer.ID ) (peers iter.ResultIter [types.Record ], err error ) {
336+ m := newMeasurement ("FindPeers" )
337+
338+ url := c .baseURL + "/routing/v1/peers/" + peer .ToCid (pid ).String ()
339+ req , err := http .NewRequestWithContext (ctx , http .MethodGet , url , nil )
340+ if err != nil {
341+ return nil , err
342+ }
343+ req .Header .Set ("Accept" , c .accepts )
344+
345+ m .host = req .Host
346+
347+ start := c .clock .Now ()
348+ resp , err := c .httpClient .Do (req )
349+
350+ m .err = err
351+ m .latency = c .clock .Since (start )
352+
353+ if err != nil {
354+ m .record (ctx )
355+ return nil , err
356+ }
357+
358+ m .statusCode = resp .StatusCode
359+ if resp .StatusCode == http .StatusNotFound {
360+ resp .Body .Close ()
361+ m .record (ctx )
362+ return iter.FromSlice [iter.Result [types.Record ]](nil ), nil
363+ }
364+
365+ if resp .StatusCode != http .StatusOK {
366+ err := httpError (resp .StatusCode , resp .Body )
367+ resp .Body .Close ()
368+ m .record (ctx )
369+ return nil , err
370+ }
371+
372+ respContentType := resp .Header .Get ("Content-Type" )
373+ mediaType , _ , err := mime .ParseMediaType (respContentType )
374+ if err != nil {
375+ resp .Body .Close ()
376+ m .err = err
377+ m .record (ctx )
378+ return nil , fmt .Errorf ("parsing Content-Type: %w" , err )
379+ }
380+
381+ m .mediaType = mediaType
382+
383+ var skipBodyClose bool
384+ defer func () {
385+ if ! skipBodyClose {
386+ resp .Body .Close ()
387+ }
388+ }()
389+
390+ var it iter.ResultIter [types.Record ]
391+ switch mediaType {
392+ case mediaTypeJSON :
393+ parsedResp := & jsontypes.PeersResponse {}
394+ err = json .NewDecoder (resp .Body ).Decode (parsedResp )
395+ var sliceIt iter.Iter [types.Record ] = iter .FromSlice (parsedResp .Peers )
396+ it = iter .ToResultIter (sliceIt )
397+ case mediaTypeNDJSON :
398+ skipBodyClose = true
399+ it = ndjson .NewRecordsIter (resp .Body )
400+ default :
401+ logger .Errorw ("unknown media type" , "MediaType" , mediaType , "ContentType" , respContentType )
402+ return nil , errors .New ("unknown content type" )
403+ }
404+
405+ return & measuringIter [iter.Result [types.Record ]]{Iter : it , ctx : ctx , m : m }, nil
406+ }
407+
408+ func (c * client ) GetIPNS (ctx context.Context , name ipns.Name ) (* ipns.Record , error ) {
331409 url := c .baseURL + "/routing/v1/ipns/" + name .String ()
332410
333411 httpReq , err := http .NewRequestWithContext (ctx , http .MethodGet , url , nil )
@@ -365,7 +443,7 @@ func (c *client) FindIPNSRecord(ctx context.Context, name ipns.Name) (*ipns.Reco
365443 return record , nil
366444}
367445
368- func (c * client ) ProvideIPNSRecord (ctx context.Context , name ipns.Name , record * ipns.Record ) error {
446+ func (c * client ) PutIPNS (ctx context.Context , name ipns.Name , record * ipns.Record ) error {
369447 url := c .baseURL + "/routing/v1/ipns/" + name .String ()
370448
371449 rawRecord , err := ipns .MarshalRecord (record )
0 commit comments