bitswap.go 6.05 KB
Newer Older
1 2 3
package commands

import (
Jeromy's avatar
Jeromy committed
4
	"fmt"
5 6
	"io"

7
	cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
Jan Winkelmann's avatar
Jan Winkelmann committed
8
	e "github.com/ipfs/go-ipfs/core/commands/e"
Overbool's avatar
Overbool committed
9

Jakub Sztandera's avatar
Jakub Sztandera committed
10 11 12 13 14
	humanize "github.com/dustin/go-humanize"
	bitswap "github.com/ipfs/go-bitswap"
	decision "github.com/ipfs/go-bitswap/decision"
	cidutil "github.com/ipfs/go-cidutil"
	cmds "github.com/ipfs/go-ipfs-cmds"
Raúl Kripalani's avatar
Raúl Kripalani committed
15
	peer "github.com/libp2p/go-libp2p-core/peer"
16 17 18
)

var BitswapCmd = &cmds.Command{
Steven Allen's avatar
Steven Allen committed
19
	Helptext: cmds.HelpText{
20
		Tagline:          "Interact with the bitswap agent.",
21 22
		ShortDescription: ``,
	},
Jan Winkelmann's avatar
Jan Winkelmann committed
23

24
	Subcommands: map[string]*cmds.Command{
25
		"stat":      bitswapStatCmd,
Overbool's avatar
Overbool committed
26 27 28
		"wantlist":  showWantlistCmd,
		"ledger":    ledgerCmd,
		"reprovide": reprovideCmd,
29 30 31
	},
}

Kejie Zhang's avatar
Kejie Zhang committed
32 33 34 35
const (
	peerOptionName = "peer"
)

Overbool's avatar
Overbool committed
36
var showWantlistCmd = &cmds.Command{
Steven Allen's avatar
Steven Allen committed
37
	Helptext: cmds.HelpText{
Richard Littauer's avatar
Richard Littauer committed
38
		Tagline: "Show blocks currently on the wantlist.",
39
		ShortDescription: `
Richard Littauer's avatar
Richard Littauer committed
40
Print out all blocks currently on the bitswap wantlist for the local peer.`,
41
	},
Steven Allen's avatar
Steven Allen committed
42 43
	Options: []cmds.Option{
		cmds.StringOption(peerOptionName, "p", "Specify which peer to show wantlist for. Default: self."),
44
	},
45
	Type: KeyList{},
Overbool's avatar
Overbool committed
46 47
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
		nd, err := cmdenv.GetNode(env)
48
		if err != nil {
Overbool's avatar
Overbool committed
49
			return err
50
		}
51

52
		if !nd.IsOnline {
Overbool's avatar
Overbool committed
53
			return ErrNotOnline
54 55
		}

56 57
		bs, ok := nd.Exchange.(*bitswap.Bitswap)
		if !ok {
Overbool's avatar
Overbool committed
58
			return e.TypeErr(bs, nd.Exchange)
59
		}
60

Overbool's avatar
Overbool committed
61
		pstr, found := req.Options[peerOptionName].(string)
62
		if found {
63
			pid, err := peer.Decode(pstr)
64
			if err != nil {
Overbool's avatar
Overbool committed
65
				return err
66
			}
Overbool's avatar
Overbool committed
67 68
			if pid != nd.Identity {
				return cmds.EmitOnce(res, &KeyList{bs.WantlistForPeer(pid)})
Jeromy's avatar
Jeromy committed
69
			}
70
		}
Overbool's avatar
Overbool committed
71

72
		return cmds.EmitOnce(res, &KeyList{bs.GetWantlist()})
73
	},
Overbool's avatar
Overbool committed
74 75
	Encoders: cmds.EncoderMap{
		cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *KeyList) error {
76 77 78 79
			enc, err := cmdenv.GetLowLevelCidEncoder(req)
			if err != nil {
				return err
			}
Overbool's avatar
Overbool committed
80 81
			// sort the keys first
			cidutil.Sort(out.Keys)
Overbool's avatar
Overbool committed
82
			for _, key := range out.Keys {
83
				fmt.Fprintln(w, enc.Encode(key))
Overbool's avatar
Overbool committed
84 85 86
			}
			return nil
		}),
87 88 89
	},
}

90 91
const (
	bitswapVerboseOptionName = "verbose"
myself659's avatar
myself659 committed
92
	bitswapHumanOptionName   = "human"
93 94
)

95
var bitswapStatCmd = &cmds.Command{
Steven Allen's avatar
Steven Allen committed
96
	Helptext: cmds.HelpText{
Richard Littauer's avatar
Richard Littauer committed
97
		Tagline:          "Show some diagnostic information on the bitswap agent.",
98 99
		ShortDescription: ``,
	},
Steven Allen's avatar
Steven Allen committed
100 101 102
	Options: []cmds.Option{
		cmds.BoolOption(bitswapVerboseOptionName, "v", "Print extra information"),
		cmds.BoolOption(bitswapHumanOptionName, "Print sizes in human readable format (e.g., 1K 234M 2G)"),
103
	},
104
	Type: bitswap.Stat{},
keks's avatar
keks committed
105
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
106
		nd, err := cmdenv.GetNode(env)
107
		if err != nil {
keks's avatar
keks committed
108
			return err
109 110
		}

111
		if !nd.IsOnline {
Steven Allen's avatar
Steven Allen committed
112
			return cmds.Errorf(cmds.ErrClient, ErrNotOnline.Error())
113 114
		}

115 116
		bs, ok := nd.Exchange.(*bitswap.Bitswap)
		if !ok {
keks's avatar
keks committed
117
			return e.TypeErr(bs, nd.Exchange)
118 119 120 121
		}

		st, err := bs.Stat()
		if err != nil {
keks's avatar
keks committed
122
			return err
123 124
		}

keks's avatar
keks committed
125
		return cmds.EmitOnce(res, st)
126
	},
Jan Winkelmann's avatar
Jan Winkelmann committed
127
	Encoders: cmds.EncoderMap{
Overbool's avatar
Overbool committed
128
		cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, s *bitswap.Stat) error {
129 130 131 132
			enc, err := cmdenv.GetLowLevelCidEncoder(req)
			if err != nil {
				return err
			}
133
			verbose, _ := req.Options[bitswapVerboseOptionName].(bool)
myself659's avatar
myself659 committed
134
			human, _ := req.Options[bitswapHumanOptionName].(bool)
135

Jan Winkelmann's avatar
Jan Winkelmann committed
136
			fmt.Fprintln(w, "bitswap status")
Overbool's avatar
Overbool committed
137 138 139
			fmt.Fprintf(w, "\tprovides buffer: %d / %d\n", s.ProvideBufLen, bitswap.HasBlockBufferSize)
			fmt.Fprintf(w, "\tblocks received: %d\n", s.BlocksReceived)
			fmt.Fprintf(w, "\tblocks sent: %d\n", s.BlocksSent)
myself659's avatar
myself659 committed
140 141 142 143 144 145 146
			if human {
				fmt.Fprintf(w, "\tdata received: %s\n", humanize.Bytes(s.DataReceived))
				fmt.Fprintf(w, "\tdata sent: %s\n", humanize.Bytes(s.DataSent))
			} else {
				fmt.Fprintf(w, "\tdata received: %d\n", s.DataReceived)
				fmt.Fprintf(w, "\tdata sent: %d\n", s.DataSent)
			}
Overbool's avatar
Overbool committed
147
			fmt.Fprintf(w, "\tdup blocks received: %d\n", s.DupBlksReceived)
myself659's avatar
myself659 committed
148 149 150 151 152
			if human {
				fmt.Fprintf(w, "\tdup data received: %s\n", humanize.Bytes(s.DupDataReceived))
			} else {
				fmt.Fprintf(w, "\tdup data received: %d\n", s.DupDataReceived)
			}
Overbool's avatar
Overbool committed
153 154
			fmt.Fprintf(w, "\twantlist [%d keys]\n", len(s.Wantlist))
			for _, k := range s.Wantlist {
155
				fmt.Fprintf(w, "\t\t%s\n", enc.Encode(k))
Jeromy's avatar
Jeromy committed
156
			}
157

Overbool's avatar
Overbool committed
158
			fmt.Fprintf(w, "\tpartners [%d]\n", len(s.Peers))
159 160 161 162
			if verbose {
				for _, p := range s.Peers {
					fmt.Fprintf(w, "\t\t%s\n", p)
				}
163
			}
Jan Winkelmann's avatar
Jan Winkelmann committed
164 165 166

			return nil
		}),
167 168
	},
}
169

Overbool's avatar
Overbool committed
170
var ledgerCmd = &cmds.Command{
Steven Allen's avatar
Steven Allen committed
171
	Helptext: cmds.HelpText{
172 173 174 175 176 177 178
		Tagline: "Show the current ledger for a peer.",
		ShortDescription: `
The Bitswap decision engine tracks the number of bytes exchanged between IPFS
nodes, and stores this information as a collection of ledgers. This command
prints the ledger associated with a given peer.
`,
	},
Steven Allen's avatar
Steven Allen committed
179 180
	Arguments: []cmds.Argument{
		cmds.StringArg("peer", true, false, "The PeerID (B58) of the ledger to inspect."),
181 182
	},
	Type: decision.Receipt{},
Overbool's avatar
Overbool committed
183 184
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
		nd, err := cmdenv.GetNode(env)
185
		if err != nil {
Overbool's avatar
Overbool committed
186
			return err
187 188
		}

189
		if !nd.IsOnline {
Overbool's avatar
Overbool committed
190
			return ErrNotOnline
191 192 193 194
		}

		bs, ok := nd.Exchange.(*bitswap.Bitswap)
		if !ok {
Overbool's avatar
Overbool committed
195
			return e.TypeErr(bs, nd.Exchange)
196 197
		}

198
		partner, err := peer.Decode(req.Arguments[0])
199
		if err != nil {
Overbool's avatar
Overbool committed
200
			return err
201
		}
Overbool's avatar
Overbool committed
202

203
		return cmds.EmitOnce(res, bs.LedgerForPeer(partner))
204
	},
Overbool's avatar
Overbool committed
205 206 207
	Encoders: cmds.EncoderMap{
		cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *decision.Receipt) error {
			fmt.Fprintf(w, "Ledger for %s\n"+
208 209 210 211 212 213
				"Debt ratio:\t%f\n"+
				"Exchanges:\t%d\n"+
				"Bytes sent:\t%d\n"+
				"Bytes received:\t%d\n\n",
				out.Peer, out.Value, out.Exchanged,
				out.Sent, out.Recv)
Overbool's avatar
Overbool committed
214 215
			return nil
		}),
216 217
	},
}
218

Overbool's avatar
Overbool committed
219
var reprovideCmd = &cmds.Command{
Steven Allen's avatar
Steven Allen committed
220
	Helptext: cmds.HelpText{
221 222 223 224 225
		Tagline: "Trigger reprovider.",
		ShortDescription: `
Trigger reprovider to announce our data to network.
`,
	},
Overbool's avatar
Overbool committed
226 227
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
		nd, err := cmdenv.GetNode(env)
228
		if err != nil {
Overbool's avatar
Overbool committed
229
			return err
230 231
		}

232
		if !nd.IsOnline {
Overbool's avatar
Overbool committed
233
			return ErrNotOnline
234 235
		}

236
		err = nd.Provider.Reprovide(req.Context)
237
		if err != nil {
Overbool's avatar
Overbool committed
238
			return err
239
		}
Jan Winkelmann's avatar
Jan Winkelmann committed
240

Overbool's avatar
Overbool committed
241
		return nil
242 243
	},
}