generated from ipfs/ipfs-repository-template
-
Notifications
You must be signed in to change notification settings - Fork 100
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(examples): routing v1 client cli
- Loading branch information
Showing
5 changed files
with
238 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# 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 routing-client | ||
``` | ||
|
||
## Usage | ||
|
||
First, you will need a Routing V1 server. For that, you can potentially use [Kubo], | ||
which supports [exposing](https://github.com/ipfs/kubo/blob/master/docs/config.md#gatewayexposeroutingapi) | ||
a Routing V1 endpoint. For the commands below, we assume the endpoint is `http://127.0.0.1:8080`. | ||
|
||
### Find CID Providers | ||
|
||
To find providers, provide the flag `-c` with the [CID] of the content you're looking for: | ||
|
||
```console | ||
$ ./routing-client -e http://127.0.0.1:8080 -c 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 `-p` with the [Peer ID] of the peer you're looking for: | ||
|
||
|
||
```console | ||
$ ./routing-client -e http://127.0.0.1:8080 -p 12D3KooWC9L4RjPGgqpzBUBkcVpKjJYofCkC5i5QdQftg1LdsFb2 | ||
|
||
12D3KooWC9L4RjPGgqpzBUBkcVpKjJYofCkC5i5QdQftg1LdsFb2 | ||
Protocols: [] | ||
Addresses: [/ip4/198.244.201.187/tcp/4001] | ||
``` | ||
|
||
### Get an IPNS Record | ||
|
||
To find an IPNS record, provide the flag `-n` with the [IPNS Name] you're trying to find a record for: | ||
|
||
```console | ||
$ ./routing-client -e http://127.0.0.1:8080 -n /ipns/k51qzi5uqu5diuz0h5tjqama8qbmyxusvqz2hfgn5go5l07l9k2ubqa09m7toe | ||
|
||
/ipns/k51qzi5uqu5diuz0h5tjqama8qbmyxusvqz2hfgn5go5l07l9k2ubqa09m7toe | ||
Value: /ipfs/QmUGMoVz62ZARyxkrdEiwmFZanTwVWLLu6EAWvbWHNcwR8 | ||
``` | ||
|
||
[Kubo]: https://github.com/ipfs/kubo | ||
[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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"flag" | ||
"fmt" | ||
"log" | ||
"time" | ||
|
||
"github.com/ipfs/boxo/ipns" | ||
"github.com/ipfs/boxo/routing/http/client" | ||
"github.com/ipfs/boxo/routing/http/types" | ||
"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("c", "", "cid to find") | ||
pidPtr := flag.String("p", "", "peer to find") | ||
namePtr := flag.String("n", "", "ipns name to retrieve record for") | ||
flag.Parse() | ||
|
||
// Creates a new Delegated Routing V1 client. | ||
client, err := client.New(*gatewayUrlPtr) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
timeout := time.Duration((*timeoutPtr)) * time.Second | ||
ctx, cancel := context.WithTimeout(context.Background(), timeout) | ||
defer cancel() | ||
|
||
if *cidPtr != "" { | ||
err = findProviders(ctx, client, *cidPtr) | ||
} else if *pidPtr != "" { | ||
err = findPeers(ctx, client, *pidPtr) | ||
} else if *namePtr != "" { | ||
err = findIPNS(ctx, client, *namePtr) | ||
} else { | ||
err = errors.New("cid or peer must be provided") | ||
} | ||
|
||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
} | ||
|
||
func findProviders(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. | ||
provIter, err := client.FindProviders(ctx, contentCid) | ||
if err != nil { | ||
return err | ||
} | ||
defer provIter.Close() | ||
|
||
// 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 provIter.Next() { | ||
res := provIter.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.Println(record.ID) | ||
fmt.Println("\tProtocols:", record.Protocols) | ||
fmt.Println("\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 findPeers(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. | ||
provIter, err := client.FindPeers(ctx, pid) | ||
if err != nil { | ||
return err | ||
} | ||
defer provIter.Close() | ||
|
||
// 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 provIter.Next() { | ||
res := provIter.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.Println(record.ID) | ||
fmt.Println("\tProtocols:", record.Protocols) | ||
fmt.Println("\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(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 | ||
} | ||
|
||
// Ask for a record. [client.GetIPNS] validates the record for us. | ||
record, err := client.GetIPNS(ctx, name) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
v, err := record.Value() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
fmt.Printf("/ipns/%s\n", name) | ||
fmt.Println("\tValue:", v.String()) | ||
return nil | ||
} |