master
go 132 lines 3.24 KB
Raw
1 package commands
2
3 import (
4 "context"
5 "errors"
6 "fmt"
7 "io"
8
9 cmds "github.com/ipfs/go-ipfs-cmds"
10 "github.com/ipfs/kubo/core/commands/cmdenv"
11 peer "github.com/libp2p/go-libp2p/core/peer"
12 routing "github.com/libp2p/go-libp2p/core/routing"
13 )
14
15 var ErrNotDHT = errors.New("routing service is not a DHT")
16
17 var DhtCmd = &cmds.Command{
18 Status: cmds.Deprecated,
19 Helptext: cmds.HelpText{
20 Tagline: "Issue commands directly through the DHT.",
21 ShortDescription: ``,
22 },
23
24 Subcommands: map[string]*cmds.Command{
25 "query": queryDhtCmd,
26 "findprovs": RemovedDHTCmd,
27 "findpeer": RemovedDHTCmd,
28 "get": RemovedDHTCmd,
29 "put": RemovedDHTCmd,
30 "provide": RemovedDHTCmd,
31 },
32 }
33
34 // kademlia extends the routing interface with a command to get the peers closest to the target
35 type kademlia interface {
36 routing.Routing
37 GetClosestPeers(ctx context.Context, key string) ([]peer.ID, error)
38 }
39
40 var queryDhtCmd = &cmds.Command{
41 Status: cmds.Deprecated,
42 Helptext: cmds.HelpText{
43 Tagline: "Find the closest Peer IDs to a given Peer ID by querying the DHT.",
44 ShortDescription: "Outputs a list of newline-delimited Peer IDs.",
45 },
46
47 Arguments: []cmds.Argument{
48 cmds.StringArg("peerID", true, true, "The peerID to run the query against."),
49 },
50 Options: []cmds.Option{
51 cmds.BoolOption(dhtVerboseOptionName, "v", "Print extra information."),
52 },
53 Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
54 nd, err := cmdenv.GetNode(env)
55 if err != nil {
56 return err
57 }
58
59 if !nd.HasActiveDHTClient() {
60 return ErrNotDHT
61 }
62
63 id, err := peer.Decode(req.Arguments[0])
64 if err != nil {
65 return cmds.ClientError("invalid peer ID")
66 }
67
68 ctx, cancel := context.WithCancel(req.Context)
69 defer cancel()
70 ctx, events := routing.RegisterForQueryEvents(ctx)
71
72 client := nd.DHTClient
73 if nd.DHT != nil && client == nd.DHT {
74 client = nd.DHT.WAN
75 if !nd.DHT.WANActive() {
76 client = nd.DHT.LAN
77 }
78 }
79
80 if d, ok := client.(kademlia); !ok {
81 return errors.New("dht client does not support GetClosestPeers")
82 } else {
83 errCh := make(chan error, 1)
84 go func() {
85 defer close(errCh)
86 defer cancel()
87 closestPeers, err := d.GetClosestPeers(ctx, string(id))
88 for _, p := range closestPeers {
89 routing.PublishQueryEvent(ctx, &routing.QueryEvent{
90 ID: p,
91 Type: routing.FinalPeer,
92 })
93 }
94
95 if err != nil {
96 errCh <- err
97 return
98 }
99 }()
100
101 for e := range events {
102 if err := res.Emit(e); err != nil {
103 return err
104 }
105 }
106
107 return <-errCh
108 }
109 },
110 Encoders: cmds.EncoderMap{
111 cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *routing.QueryEvent) error {
112 pfm := pfuncMap{
113 routing.FinalPeer: func(obj *routing.QueryEvent, out io.Writer, verbose bool) error {
114 fmt.Fprintf(out, "%s\n", obj.ID)
115 return nil
116 },
117 }
118 verbose, _ := req.Options[dhtVerboseOptionName].(bool)
119 return printEvent(out, w, verbose, pfm)
120 }),
121 },
122 Type: routing.QueryEvent{},
123 }
124 var RemovedDHTCmd = &cmds.Command{
125 Status: cmds.Removed,
126 Helptext: cmds.HelpText{
127 Tagline: "Removed, use 'ipfs routing' instead.",
128 },
129 Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
130 return errors.New("removed, use 'ipfs routing' instead")
131 },
132 }