bitswap.go 6.13 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 15 16
	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"
	cmdkit "github.com/ipfs/go-ipfs-cmdkit"
	cmds "github.com/ipfs/go-ipfs-cmds"
	peer "github.com/libp2p/go-libp2p-peer"
17 18 19
)

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

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

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

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

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

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

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

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

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

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

112
		if !nd.IsOnline {
keks's avatar
keks committed
113
			return cmdkit.Errorf(cmdkit.ErrClient, ErrNotOnline.Error())
114 115
		}

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

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

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

Jan Winkelmann's avatar
Jan Winkelmann committed
137
			fmt.Fprintln(w, "bitswap status")
Overbool's avatar
Overbool committed
138 139 140
			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
141 142 143 144 145 146 147
			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
148
			fmt.Fprintf(w, "\tdup blocks received: %d\n", s.DupBlksReceived)
myself659's avatar
myself659 committed
149 150 151 152 153
			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
154 155
			fmt.Fprintf(w, "\twantlist [%d keys]\n", len(s.Wantlist))
			for _, k := range s.Wantlist {
156
				fmt.Fprintf(w, "\t\t%s\n", enc.Encode(k))
Jeromy's avatar
Jeromy committed
157
			}
158

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

			return nil
		}),
168 169
	},
}
170

Overbool's avatar
Overbool committed
171
var ledgerCmd = &cmds.Command{
Jan Winkelmann's avatar
Jan Winkelmann committed
172
	Helptext: cmdkit.HelpText{
173 174 175 176 177 178 179
		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.
`,
	},
Jan Winkelmann's avatar
Jan Winkelmann committed
180 181
	Arguments: []cmdkit.Argument{
		cmdkit.StringArg("peer", true, false, "The PeerID (B58) of the ledger to inspect."),
182 183
	},
	Type: decision.Receipt{},
Overbool's avatar
Overbool committed
184 185
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
		nd, err := cmdenv.GetNode(env)
186
		if err != nil {
Overbool's avatar
Overbool committed
187
			return err
188 189
		}

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

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

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

204
		return cmds.EmitOnce(res, bs.LedgerForPeer(partner))
205
	},
Overbool's avatar
Overbool committed
206 207 208
	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"+
209 210 211 212 213 214
				"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
215 216
			return nil
		}),
217 218
	},
}
219

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

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

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

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