-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
170 lines (145 loc) · 4.71 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
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 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 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()
// 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 recordsIter.Next() {
res := recordsIter.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
}
fmt.Fprintln(w, res.Val.ID)
fmt.Fprintln(w, "\tProtocols:", res.Val.Protocols)
fmt.Fprintln(w, "\tAddresses:", res.Val.Addrs)
}
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
}