diff --git a/CHANGELOG.md b/CHANGELOG.md index bb864a5a7..2afccc4b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ The following emojis are used to highlight certain changes: * 🛠 The `IPFSBackend` interface was updated to make the responses of the `Head` method more explicit. It now returns a `HeadResponse` instead of a `files.Node`. +* `boxo/routing/http/client.Client` is now exported. This means you can now pass + it around functions, or add it to a struct if you want. ### Removed diff --git a/examples/README.md b/examples/README.md index 1c63f087d..c0795436d 100644 --- a/examples/README.md +++ b/examples/README.md @@ -9,3 +9,4 @@ Let us know if you find any issue or if you want to contribute and add a new tut - [Fetching a UnixFS file by CID](./unixfs-file-cid) - [Gateway backed by a CAR file](./gateway/car) - [Gateway backed by a remote blockstore and IPNS resolver](./gateway/proxy) +- [Delegated Routing V1 Command Line Client](./routing/delegated-routing-client/) diff --git a/examples/go.mod b/examples/go.mod index 790573a69..24bcbe929 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -125,6 +125,7 @@ require ( github.com/quic-go/quic-go v0.38.0 // indirect github.com/quic-go/webtransport-go v0.5.3 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect + github.com/samber/lo v1.36.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb // indirect github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc // indirect diff --git a/examples/go.sum b/examples/go.sum index eaec6f954..93ee14dd3 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -216,6 +216,7 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= @@ -478,6 +479,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/samber/lo v1.36.0 h1:4LaOxH1mHnbDGhTVE0i1z8v/lWaQW8AIfOD3HU4mSaw= +github.com/samber/lo v1.36.0/go.mod h1:HLeWcJRRyLKp3+/XBJvOrerCQn9mhdKMHyd7IRlgeQ8= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= @@ -530,6 +533,7 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= +github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M= github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb h1:Ywfo8sUltxogBpFuMOFRrrSifO788kAFxmvVw31PtQQ= github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb/go.mod h1:ikPs9bRWicNw3S7XpJ8sK/smGwU9WcSVU3dy9qahYBM= diff --git a/examples/routing/delegated-routing-client/.gitignore b/examples/routing/delegated-routing-client/.gitignore new file mode 100644 index 000000000..2555457e2 --- /dev/null +++ b/examples/routing/delegated-routing-client/.gitignore @@ -0,0 +1 @@ +delegated-routing-client \ No newline at end of file diff --git a/examples/routing/delegated-routing-client/README.md b/examples/routing/delegated-routing-client/README.md new file mode 100644 index 000000000..3e34e4531 --- /dev/null +++ b/examples/routing/delegated-routing-client/README.md @@ -0,0 +1,71 @@ +# Delegated Routing V1 Command Line Client + +This is an example of how to use the Delegated Routing V1 HTTP client from Boxo. +In this package, we build a small command line tool that allows you to connect to +a Routing V1 endpoint and fetch content providers, peer information, as well as +IPNS records for a certain IPNS name. + +## Build + +```bash +> go build -o delegated-routing-client +``` + +## Usage + +First, you will need a HTTP endpoint compatible with [Delegated Routing V1 Specification][Specification]. +For that, you can potentially use [Kubo], which supports [exposing][kubo-conf] +a `/routing/v1` endpoint. For the commands below, we assume the HTTP server that +provides the endpoint is `http://127.0.0.1:8080`. + +### Find CID Providers + +To find providers, provide the flag `-cid` with the [CID] of the content you're looking for: + +```console +$ ./delegated-routing-client -e http://127.0.0.1:8080 -cid bafkreifjjcie6lypi6ny7amxnfftagclbuxndqonfipmb64f2km2devei4 + +12D3KooWEfL19QqRGGLraaAYw1XA3dtDdVRYaHt6jymFxcuQo3Zm + Protocols: [] + Addresses: [/ip4/163.47.51.218/tcp/28131] +12D3KooWK53GAx2g2UUYfJHHjxDbVLeDgGxNMHXDWeJa5KgMhTD2 + Protocols: [] + Addresses: [/ip4/195.167.147.43/udp/8888/quic /ip4/195.167.147.43/tcp/8888] +12D3KooWCpr8kACTRLKrPy4LPpSX7LXvKQ7eYqTmY8CBvgK5HZgB + Protocols: [] + Addresses: [/ip4/163.47.49.234/tcp/28102] +12D3KooWC9L4RjPGgqpzBUBkcVpKjJYofCkC5i5QdQftg1LdsFb2 + Protocols: [] + Addresses: [/ip4/198.244.201.187/tcp/4001] +``` + +### Find Peer Information + +To find a peer, provide the flag `-peer` with the [Peer ID] of the peer you're looking for: + + +```console +$ ./delegated-routing-client -e http://127.0.0.1:8080 -peer 12D3KooWC9L4RjPGgqpzBUBkcVpKjJYofCkC5i5QdQftg1LdsFb2 + +12D3KooWC9L4RjPGgqpzBUBkcVpKjJYofCkC5i5QdQftg1LdsFb2 + Protocols: [] + Addresses: [/ip4/198.244.201.187/tcp/4001] +``` + +### Get an IPNS Record + +To find an IPNS record, provide the flag `-ipns` with the [IPNS Name] you're trying to find a record for: + +```console +$ ./delegated-routing-client -e http://127.0.0.1:8080 -ipns /ipns/k51qzi5uqu5diuz0h5tjqama8qbmyxusvqz2hfgn5go5l07l9k2ubqa09m7toe + +/ipns/k51qzi5uqu5diuz0h5tjqama8qbmyxusvqz2hfgn5go5l07l9k2ubqa09m7toe + Value: /ipfs/QmUGMoVz62ZARyxkrdEiwmFZanTwVWLLu6EAWvbWHNcwR8 +``` + +[Specification]: https://specs.ipfs.tech/routing/http-routing-v1/ +[Kubo]: https://github.com/ipfs/kubo +[kubo-conf]: https://github.com/ipfs/kubo/blob/master/docs/config.md#gatewayexposeroutingapi +[CID]: https://docs.ipfs.tech/concepts/content-addressing/#what-is-a-cid +[Peer ID]: https://docs.libp2p.io/concepts/fundamentals/peers/#peer-id +[IPNS Name]: https://specs.ipfs.tech/ipns/ipns-record/#ipns-name diff --git a/examples/routing/delegated-routing-client/main.go b/examples/routing/delegated-routing-client/main.go new file mode 100644 index 000000000..0b586d4bf --- /dev/null +++ b/examples/routing/delegated-routing-client/main.go @@ -0,0 +1,148 @@ +package main + +import ( + "context" + "errors" + "flag" + "fmt" + "io" + "log" + "os" + "time" + + "github.com/ipfs/boxo/ipns" + "github.com/ipfs/boxo/routing/http/client" + "github.com/ipfs/boxo/routing/http/types" + "github.com/ipfs/boxo/routing/http/types/iter" + "github.com/ipfs/go-cid" + "github.com/libp2p/go-libp2p/core/peer" +) + +func main() { + gatewayUrlPtr := flag.String("e", "", "routing v1 endpoint to use") + timeoutPtr := flag.Int("t", 10, "timeout in seconds for lookup") + cidPtr := flag.String("cid", "", "cid to find") + pidPtr := flag.String("peer", "", "peer to find") + namePtr := flag.String("ipns", "", "ipns name to retrieve record for") + flag.Parse() + + if err := run(os.Stdout, *gatewayUrlPtr, *cidPtr, *pidPtr, *namePtr, *timeoutPtr); err != nil { + log.Fatal(err) + } +} + +func run(w io.Writer, gatewayURL, cidStr, pidStr, nameStr string, timeoutSeconds int) error { + // Creates a new Delegated Routing V1 client. + client, err := client.New(gatewayURL) + if err != nil { + return err + } + + timeout := time.Duration(timeoutSeconds) * time.Second + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + if cidStr != "" { + return findProviders(w, ctx, client, cidStr) + } else if pidStr != "" { + return findPeers(w, ctx, client, pidStr) + } else if nameStr != "" { + return findIPNS(w, ctx, client, nameStr) + } else { + return errors.New("cid or peer must be provided") + } +} + +func findProviders(w io.Writer, ctx context.Context, client *client.Client, cidStr string) error { + // Parses the given CID to lookup the providers for. + contentCid, err := cid.Parse(cidStr) + if err != nil { + return err + } + + // Ask for providers providing the given content CID. + recordsIter, err := client.FindProviders(ctx, contentCid) + if err != nil { + return err + } + defer recordsIter.Close() + return printIter(w, recordsIter) +} + +func findPeers(w io.Writer, ctx context.Context, client *client.Client, pidStr string) error { + // Parses the given Peer ID to lookup the information for. + pid, err := peer.Decode(pidStr) + if err != nil { + return err + } + + // Ask for information about the peer with the given peer ID. + recordsIter, err := client.FindPeers(ctx, pid) + if err != nil { + return err + } + defer recordsIter.Close() + return printIter(w, recordsIter) +} + +func printIter(w io.Writer, iter iter.ResultIter[types.Record]) error { + // The response is streamed. Alternatively, you could use [iter.ReadAll] + // to fetch all the results all at once, instead of iterating as they are + // streamed. + for iter.Next() { + res := iter.Val() + + // Check for error, but do not complain if we exceeded the timeout. We are + // expecting that to happen: we explicitly defined a timeout. + if res.Err != nil { + if !errors.Is(res.Err, context.DeadlineExceeded) { + return res.Err + } + + return nil + } + + switch res.Val.GetSchema() { + case types.SchemaPeer: + record := res.Val.(*types.PeerRecord) + fmt.Fprintln(w, record.ID) + fmt.Fprintln(w, "\tProtocols:", record.Protocols) + fmt.Fprintln(w, "\tAddresses:", record.Addrs) + default: + // You may not want to fail here, it's up to you. You can just handle + // the schemas you want, or that you know, but not fail. + log.Printf("unrecognized schema: %s", res.Val.GetSchema()) + } + } + + return nil +} + +func findIPNS(w io.Writer, ctx context.Context, client *client.Client, nameStr string) error { + // Parses the given name string to get a record for. + name, err := ipns.NameFromString(nameStr) + if err != nil { + return err + } + + // Fetch an IPNS record for the given name. [client.Client.GetIPNS] verifies + // if the retrieved record is valid against the given name, and errors otherwise. + record, err := client.GetIPNS(ctx, name) + if err != nil { + return err + } + + fmt.Fprintf(w, "/ipns/%s\n", name) + v, err := record.Value() + if err != nil { + return err + } + + // Since [client.Client.GetIPNS] verifies if the retrieved record is valid, we + // do not need to verify it again. However, if you were not using this specific + // client, but using some other tool, you should always validate the IPNS Record + // using the [ipns.Validate] or [ipns.ValidateWithName] functions. + fmt.Fprintln(w, "\tSignature: VALID") + fmt.Fprintln(w, "\tValue:", v.String()) + return nil +} diff --git a/examples/routing/delegated-routing-client/main_test.go b/examples/routing/delegated-routing-client/main_test.go new file mode 100644 index 000000000..7ad813f13 --- /dev/null +++ b/examples/routing/delegated-routing-client/main_test.go @@ -0,0 +1,96 @@ +package main + +import ( + "bytes" + "crypto/rand" + "fmt" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/ipfs/boxo/coreiface/path" + "github.com/ipfs/boxo/ipns" + ipfspath "github.com/ipfs/boxo/path" + "github.com/ipfs/go-cid" + "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestFindProviders(t *testing.T) { + cidStr := "bafkreifjjcie6lypi6ny7amxnfftagclbuxndqonfipmb64f2km2devei4" + + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/routing/v1/providers/"+cidStr { + w.Header().Set("Content-Type", "application/x-ndjson") + w.Write([]byte(`{"Schema":"peer","ID":"12D3KooWM8sovaEGU1bmiWGWAzvs47DEcXKZZTuJnpQyVTkRs2Vn","Addrs":["/ip4/111.222.222.111/tcp/5734"],"Protocols":["transport-bitswap"]}` + "\n")) + w.Write([]byte(`{"Schema":"peer","ID":"12D3KooWB6RAWgcmHAP7TGEGK7utV2ZuqSzX1DNjRa97TtJ7139n","Addrs":["/ip4/127.0.0.1/tcp/5734"],"Protocols":["transport-horse"]}` + "\n")) + } + })) + t.Cleanup(ts.Close) + + out := &bytes.Buffer{} + err := run(out, ts.URL, cidStr, "", "", 1) + assert.Contains(t, out.String(), "12D3KooWM8sovaEGU1bmiWGWAzvs47DEcXKZZTuJnpQyVTkRs2Vn\n\tProtocols: [transport-bitswap]\n\tAddresses: [/ip4/111.222.222.111/tcp/5734]\n") + assert.Contains(t, out.String(), "12D3KooWB6RAWgcmHAP7TGEGK7utV2ZuqSzX1DNjRa97TtJ7139n\n\tProtocols: [transport-horse]\n\tAddresses: [/ip4/127.0.0.1/tcp/5734]\n") + assert.NoError(t, err) +} + +func TestFindPeers(t *testing.T) { + pidStr := "bafzaajaiaejcbkboq2tin6dkdc2vinbbn2dgowzn3u5izpjwxejheogw23scafkz" + + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/routing/v1/peers/"+pidStr { + w.Header().Set("Content-Type", "application/x-ndjson") + w.Write([]byte(`{"Schema":"peer","ID":"12D3KooWM8sovaEGU1bmiWGWAzvs47DEcXKZZTuJnpQyVTkRs2Vn","Addrs":["/ip4/111.222.222.111/tcp/5734"],"Protocols":["transport-bitswap"]}` + "\n")) + } + })) + t.Cleanup(ts.Close) + + out := &bytes.Buffer{} + err := run(out, ts.URL, "", pidStr, "", 1) + assert.Contains(t, out.String(), "12D3KooWM8sovaEGU1bmiWGWAzvs47DEcXKZZTuJnpQyVTkRs2Vn\n\tProtocols: [transport-bitswap]\n\tAddresses: [/ip4/111.222.222.111/tcp/5734]\n") + assert.NoError(t, err) +} + +func TestGetIPNS(t *testing.T) { + name, rec := makeNameAndRecord(t) + + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/routing/v1/ipns/"+name.String() { + w.Header().Set("Content-Type", "application/vnd.ipfs.ipns-record") + w.Write(rec) + } + })) + t.Cleanup(ts.Close) + + out := &bytes.Buffer{} + err := run(out, ts.URL, "", "", name.String(), 1) + assert.Contains(t, out.String(), fmt.Sprintf("/ipns/%s\n\tSignature: VALID\n\tValue: /ipfs/bafkreifjjcie6lypi6ny7amxnfftagclbuxndqonfipmb64f2km2devei4\n", name.String())) + assert.NoError(t, err) +} + +func makeNameAndRecord(t *testing.T) (ipns.Name, []byte) { + sk, _, err := crypto.GenerateEd25519Key(rand.Reader) + require.NoError(t, err) + + pid, err := peer.IDFromPrivateKey(sk) + require.NoError(t, err) + + cid, err := cid.Decode("bafkreifjjcie6lypi6ny7amxnfftagclbuxndqonfipmb64f2km2devei4") + require.NoError(t, err) + + path := path.IpfsPath(cid) + eol := time.Now().Add(time.Hour * 48) + ttl := time.Second * 20 + + record, err := ipns.NewRecord(sk, ipfspath.FromString(path.String()), 1, eol, ttl) + require.NoError(t, err) + + rawRecord, err := ipns.MarshalRecord(record) + require.NoError(t, err) + + return ipns.NameFromPeer(pid), rawRecord +} diff --git a/routing/http/client/client.go b/routing/http/client/client.go index 4a0d29b33..39dd698cb 100644 --- a/routing/http/client/client.go +++ b/routing/http/client/client.go @@ -28,7 +28,7 @@ import ( ) var ( - _ contentrouter.Client = &client{} + _ contentrouter.Client = &Client{} logger = logging.Logger("routing/http/client") defaultHTTPClient = &http.Client{ Transport: &ResponseBodyLimitedTransport{ @@ -45,7 +45,7 @@ const ( mediaTypeIPNSRecord = "application/vnd.ipfs.ipns-record" ) -type client struct { +type Client struct { baseURL string httpClient httpClient clock clock.Clock @@ -65,28 +65,28 @@ type client struct { // version sent a request var defaultUserAgent = moduleVersion() -var _ contentrouter.Client = &client{} +var _ contentrouter.Client = &Client{} type httpClient interface { Do(req *http.Request) (*http.Response, error) } -type Option func(*client) +type Option func(*Client) func WithIdentity(identity crypto.PrivKey) Option { - return func(c *client) { + return func(c *Client) { c.identity = identity } } func WithHTTPClient(h httpClient) Option { - return func(c *client) { + return func(c *Client) { c.httpClient = h } } func WithUserAgent(ua string) Option { - return func(c *client) { + return func(c *Client) { if ua == "" { return } @@ -103,7 +103,7 @@ func WithUserAgent(ua string) Option { } func WithProviderInfo(peerID peer.ID, addrs []multiaddr.Multiaddr) Option { - return func(c *client) { + return func(c *Client) { c.peerID = peerID for _, a := range addrs { c.addrs = append(c.addrs, types.Multiaddr{Multiaddr: a}) @@ -112,15 +112,15 @@ func WithProviderInfo(peerID peer.ID, addrs []multiaddr.Multiaddr) Option { } func WithStreamResultsRequired() Option { - return func(c *client) { + return func(c *Client) { c.accepts = mediaTypeNDJSON } } // New creates a content routing API client. // The Provider and identity parameters are option. If they are nil, the [client.ProvideBitswap] method will not function. -func New(baseURL string, opts ...Option) (*client, error) { - client := &client{ +func New(baseURL string, opts ...Option) (*Client, error) { + client := &Client{ baseURL: baseURL, httpClient: defaultHTTPClient, clock: clock.New(), @@ -160,7 +160,7 @@ func (c *measuringIter[T]) Close() error { return c.Iter.Close() } -func (c *client) FindProviders(ctx context.Context, key cid.Cid) (providers iter.ResultIter[types.Record], err error) { +func (c *Client) FindProviders(ctx context.Context, key cid.Cid) (providers iter.ResultIter[types.Record], err error) { // TODO test measurements m := newMeasurement("FindProviders") @@ -237,7 +237,7 @@ func (c *client) FindProviders(ctx context.Context, key cid.Cid) (providers iter // Deprecated: protocol-agnostic provide is being worked on in [IPIP-378]: // // [IPIP-378]: https://github.com/ipfs/specs/pull/378 -func (c *client) ProvideBitswap(ctx context.Context, keys []cid.Cid, ttl time.Duration) (time.Duration, error) { +func (c *Client) ProvideBitswap(ctx context.Context, keys []cid.Cid, ttl time.Duration) (time.Duration, error) { if c.identity == nil { return 0, errors.New("cannot provide Bitswap records without an identity") } @@ -283,7 +283,7 @@ func (c *client) ProvideBitswap(ctx context.Context, keys []cid.Cid, ttl time.Du // ProvideAsync makes a provide request to a delegated router // //lint:ignore SA1019 // ignore staticcheck -func (c *client) provideSignedBitswapRecord(ctx context.Context, bswp *types.WriteBitswapRecord) (time.Duration, error) { +func (c *Client) provideSignedBitswapRecord(ctx context.Context, bswp *types.WriteBitswapRecord) (time.Duration, error) { //lint:ignore SA1019 // ignore staticcheck req := jsontypes.WriteProvidersRequest{Providers: []types.Record{bswp}} @@ -332,7 +332,7 @@ func (c *client) provideSignedBitswapRecord(ctx context.Context, bswp *types.Wri return 0, nil } -func (c *client) FindPeers(ctx context.Context, pid peer.ID) (peers iter.ResultIter[types.Record], err error) { +func (c *Client) FindPeers(ctx context.Context, pid peer.ID) (peers iter.ResultIter[types.Record], err error) { m := newMeasurement("FindPeers") url := c.baseURL + "/routing/v1/peers/" + peer.ToCid(pid).String() @@ -405,7 +405,7 @@ func (c *client) FindPeers(ctx context.Context, pid peer.ID) (peers iter.ResultI return &measuringIter[iter.Result[types.Record]]{Iter: it, ctx: ctx, m: m}, nil } -func (c *client) GetIPNS(ctx context.Context, name ipns.Name) (*ipns.Record, error) { +func (c *Client) GetIPNS(ctx context.Context, name ipns.Name) (*ipns.Record, error) { url := c.baseURL + "/routing/v1/ipns/" + name.String() httpReq, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) @@ -443,7 +443,7 @@ func (c *client) GetIPNS(ctx context.Context, name ipns.Name) (*ipns.Record, err return record, nil } -func (c *client) PutIPNS(ctx context.Context, name ipns.Name, record *ipns.Record) error { +func (c *Client) PutIPNS(ctx context.Context, name ipns.Name, record *ipns.Record) error { url := c.baseURL + "/routing/v1/ipns/" + name.String() rawRecord, err := ipns.MarshalRecord(record) diff --git a/routing/http/client/client_test.go b/routing/http/client/client_test.go index 95683bc3f..3822862dd 100644 --- a/routing/http/client/client_test.go +++ b/routing/http/client/client_test.go @@ -67,7 +67,7 @@ type testDeps struct { server *httptest.Server peerID peer.ID addrs []multiaddr.Multiaddr - client *client + client *Client } type recordingHandler struct {