master
go 213 lines 5.65 KB
Raw
1 package commands
2
3 import (
4 "fmt"
5 "io"
6
7 cmdenv "github.com/ipfs/kubo/core/commands/cmdenv"
8
9 humanize "github.com/dustin/go-humanize"
10 bitswap "github.com/ipfs/boxo/bitswap"
11 "github.com/ipfs/boxo/bitswap/server"
12 cidutil "github.com/ipfs/go-cidutil"
13 cmds "github.com/ipfs/go-ipfs-cmds"
14 peer "github.com/libp2p/go-libp2p/core/peer"
15 )
16
17 var BitswapCmd = &cmds.Command{
18 Helptext: cmds.HelpText{
19 Tagline: "Interact with the bitswap agent.",
20 ShortDescription: ``,
21 },
22
23 Subcommands: map[string]*cmds.Command{
24 "stat": bitswapStatCmd,
25 "wantlist": showWantlistCmd,
26 "ledger": ledgerCmd,
27 "reprovide": deprecatedBitswapReprovideCmd,
28 },
29 }
30
31 const (
32 peerOptionName = "peer"
33 )
34
35 var deprecatedBitswapReprovideCmd = &cmds.Command{
36 Status: cmds.Deprecated,
37 Helptext: cmds.HelpText{
38 Tagline: "Deprecated command to announce to bitswap. Use 'ipfs routing reprovide' instead.",
39 ShortDescription: `
40 'ipfs bitswap reprovide' is a legacy plumbing command used to announce to DHT.
41 Deprecated, use modern 'ipfs routing reprovide' instead.`,
42 },
43 Run: reprovideRoutingCmd.Run, // alias to routing reprovide to not break existing users
44 }
45
46 var showWantlistCmd = &cmds.Command{
47 Helptext: cmds.HelpText{
48 Tagline: "Show blocks currently on the wantlist.",
49 ShortDescription: `
50 Print out all blocks currently on the bitswap wantlist for the local peer.`,
51 },
52 Options: []cmds.Option{
53 cmds.StringOption(peerOptionName, "p", "Specify which peer to show wantlist for. Default: self."),
54 },
55 Type: KeyList{},
56 Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
57 nd, err := cmdenv.GetNode(env)
58 if err != nil {
59 return err
60 }
61
62 if !nd.IsOnline {
63 return ErrNotOnline
64 }
65
66 bs := nd.Bitswap
67
68 pstr, found := req.Options[peerOptionName].(string)
69 if found {
70 pid, err := peer.Decode(pstr)
71 if err != nil {
72 return err
73 }
74 if pid != nd.Identity {
75 return cmds.EmitOnce(res, &KeyList{bs.WantlistForPeer(pid)})
76 }
77 }
78
79 return cmds.EmitOnce(res, &KeyList{bs.GetWantlist()})
80 },
81 Encoders: cmds.EncoderMap{
82 cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *KeyList) error {
83 enc, err := cmdenv.GetCidEncoder(req)
84 if err != nil {
85 return err
86 }
87 // sort the keys first
88 cidutil.Sort(out.Keys)
89 for _, key := range out.Keys {
90 fmt.Fprintln(w, enc.Encode(key))
91 }
92 return nil
93 }),
94 },
95 }
96
97 const (
98 bitswapVerboseOptionName = "verbose"
99 bitswapHumanOptionName = "human"
100 )
101
102 var bitswapStatCmd = &cmds.Command{
103 Helptext: cmds.HelpText{
104 Tagline: "Show some diagnostic information on the bitswap agent.",
105 ShortDescription: ``,
106 },
107 Options: []cmds.Option{
108 cmds.BoolOption(bitswapVerboseOptionName, "v", "Print extra information"),
109 cmds.BoolOption(bitswapHumanOptionName, "Print sizes in human readable format (e.g., 1K 234M 2G)"),
110 },
111 Type: bitswap.Stat{},
112 Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
113 nd, err := cmdenv.GetNode(env)
114 if err != nil {
115 return err
116 }
117
118 if !nd.IsOnline {
119 return cmds.Errorf(cmds.ErrClient, "unable to run offline: %s", ErrNotOnline)
120 }
121
122 st, err := nd.Bitswap.Stat()
123 if err != nil {
124 return err
125 }
126
127 return cmds.EmitOnce(res, st)
128 },
129 Encoders: cmds.EncoderMap{
130 cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, s *bitswap.Stat) error {
131 enc, err := cmdenv.GetCidEncoder(req)
132 if err != nil {
133 return err
134 }
135 verbose, _ := req.Options[bitswapVerboseOptionName].(bool)
136 human, _ := req.Options[bitswapHumanOptionName].(bool)
137
138 fmt.Fprintln(w, "bitswap status")
139 fmt.Fprintf(w, "\tblocks received: %d\n", s.BlocksReceived)
140 fmt.Fprintf(w, "\tblocks sent: %d\n", s.BlocksSent)
141 if human {
142 fmt.Fprintf(w, "\tdata received: %s\n", humanize.Bytes(s.DataReceived))
143 fmt.Fprintf(w, "\tdata sent: %s\n", humanize.Bytes(s.DataSent))
144 } else {
145 fmt.Fprintf(w, "\tdata received: %d\n", s.DataReceived)
146 fmt.Fprintf(w, "\tdata sent: %d\n", s.DataSent)
147 }
148 fmt.Fprintf(w, "\tdup blocks received: %d\n", s.DupBlksReceived)
149 if human {
150 fmt.Fprintf(w, "\tdup data received: %s\n", humanize.Bytes(s.DupDataReceived))
151 } else {
152 fmt.Fprintf(w, "\tdup data received: %d\n", s.DupDataReceived)
153 }
154 fmt.Fprintf(w, "\twantlist [%d keys]\n", len(s.Wantlist))
155 for _, k := range s.Wantlist {
156 fmt.Fprintf(w, "\t\t%s\n", enc.Encode(k))
157 }
158
159 fmt.Fprintf(w, "\tpartners [%d]\n", len(s.Peers))
160 if verbose {
161 for _, p := range s.Peers {
162 fmt.Fprintf(w, "\t\t%s\n", p)
163 }
164 }
165
166 return nil
167 }),
168 },
169 }
170
171 var ledgerCmd = &cmds.Command{
172 Helptext: cmds.HelpText{
173 Tagline: "Show the current ledger for a peer.",
174 ShortDescription: `
175 The Bitswap decision engine tracks the number of bytes exchanged between IPFS
176 nodes, and stores this information as a collection of ledgers. This command
177 prints the ledger associated with a given peer.
178 `,
179 },
180 Arguments: []cmds.Argument{
181 cmds.StringArg("peer", true, false, "The PeerID (B58) of the ledger to inspect."),
182 },
183 Type: server.Receipt{},
184 Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
185 nd, err := cmdenv.GetNode(env)
186 if err != nil {
187 return err
188 }
189
190 if !nd.IsOnline {
191 return ErrNotOnline
192 }
193
194 partner, err := peer.Decode(req.Arguments[0])
195 if err != nil {
196 return err
197 }
198
199 return cmds.EmitOnce(res, nd.Bitswap.LedgerForPeer(partner))
200 },
201 Encoders: cmds.EncoderMap{
202 cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *server.Receipt) error {
203 fmt.Fprintf(w, "Ledger for %s\n"+
204 "Debt ratio:\t%f\n"+
205 "Exchanges:\t%d\n"+
206 "Bytes sent:\t%d\n"+
207 "Bytes received:\t%d\n\n",
208 out.Peer, out.Value, out.Exchanged,
209 out.Sent, out.Recv)
210 return nil
211 }),
212 },
213 }