bitswap.go 7.18 KB
Newer Older
1 2 3 4
package commands

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

Jan Winkelmann's avatar
Jan Winkelmann committed
8 9
	oldcmds "github.com/ipfs/go-ipfs/commands"
	e "github.com/ipfs/go-ipfs/core/commands/e"
10
	bitswap "github.com/ipfs/go-ipfs/exchange/bitswap"
11 12
	decision "github.com/ipfs/go-ipfs/exchange/bitswap/decision"

13
	cid "gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid"
14
	"gx/ipfs/QmPSBJL4momYnE7DcUyk2DVhD6rH488ZmHBGLbxNdhU44K/go-humanize"
Jan Winkelmann's avatar
Jan Winkelmann committed
15
	cmdkit "gx/ipfs/QmSNbH2A1evCCbJSDC6u3RV3GGDhgu6pRGbXHvrN89tMKf/go-ipfs-cmdkit"
keks's avatar
keks committed
16
	cmds "gx/ipfs/QmUgr8HrEkQqXfBPtj1A2UEg1V7cvhUhDsmL44wFPCJk5k/go-ipfs-cmds"
17
	peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer"
18 19 20
)

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

26
	Subcommands: map[string]*cmds.Command{
Jan Winkelmann's avatar
Jan Winkelmann committed
27 28 29
		"stat": bitswapStatCmd,
	},
	OldSubcommands: map[string]*oldcmds.Command{
30 31 32 33
		"wantlist":  showWantlistCmd,
		"unwant":    unwantCmd,
		"ledger":    ledgerCmd,
		"reprovide": reprovideCmd,
34 35 36
	},
}

Jan Winkelmann's avatar
Jan Winkelmann committed
37 38
var unwantCmd = &oldcmds.Command{
	Helptext: cmdkit.HelpText{
Richard Littauer's avatar
Richard Littauer committed
39
		Tagline: "Remove a given block from your wantlist.",
40
	},
Jan Winkelmann's avatar
Jan Winkelmann committed
41 42
	Arguments: []cmdkit.Argument{
		cmdkit.StringArg("key", true, true, "Key(s) to remove from your wantlist.").EnableStdin(),
43
	},
Jan Winkelmann's avatar
Jan Winkelmann committed
44
	Run: func(req oldcmds.Request, res oldcmds.Response) {
45 46
		nd, err := req.InvocContext().GetNode()
		if err != nil {
Jan Winkelmann's avatar
Jan Winkelmann committed
47
			res.SetError(err, cmdkit.ErrNormal)
48 49 50 51
			return
		}

		if !nd.OnlineMode() {
Jan Winkelmann's avatar
Jan Winkelmann committed
52
			res.SetError(errNotOnline, cmdkit.ErrClient)
53 54 55 56 57
			return
		}

		bs, ok := nd.Exchange.(*bitswap.Bitswap)
		if !ok {
Jan Winkelmann's avatar
Jan Winkelmann committed
58
			res.SetError(e.TypeErr(bs, nd.Exchange), cmdkit.ErrNormal)
59 60 61
			return
		}

62
		var ks []*cid.Cid
63
		for _, arg := range req.Arguments() {
Jeromy's avatar
Jeromy committed
64 65
			c, err := cid.Decode(arg)
			if err != nil {
Jan Winkelmann's avatar
Jan Winkelmann committed
66
				res.SetError(err, cmdkit.ErrNormal)
67 68 69
				return
			}

70
			ks = append(ks, c)
71 72
		}

Jeromy's avatar
Jeromy committed
73 74 75 76 77
		// TODO: This should maybe find *all* sessions for this request and cancel them?
		// (why): in reality, i think this command should be removed. Its
		// messing with the internal state of bitswap. You should cancel wants
		// by killing the command that caused the want.
		bs.CancelWants(ks, 0)
keks's avatar
keks committed
78 79

		res.SetOutput(nil)
80 81 82
	},
}

Jan Winkelmann's avatar
Jan Winkelmann committed
83 84
var showWantlistCmd = &oldcmds.Command{
	Helptext: cmdkit.HelpText{
Richard Littauer's avatar
Richard Littauer committed
85
		Tagline: "Show blocks currently on the wantlist.",
86
		ShortDescription: `
Richard Littauer's avatar
Richard Littauer committed
87
Print out all blocks currently on the bitswap wantlist for the local peer.`,
88
	},
Jan Winkelmann's avatar
Jan Winkelmann committed
89 90
	Options: []cmdkit.Option{
		cmdkit.StringOption("peer", "p", "Specify which peer to show wantlist for. Default: self."),
91
	},
92
	Type: KeyList{},
Jan Winkelmann's avatar
Jan Winkelmann committed
93
	Run: func(req oldcmds.Request, res oldcmds.Response) {
Jeromy's avatar
Jeromy committed
94
		nd, err := req.InvocContext().GetNode()
95
		if err != nil {
Jan Winkelmann's avatar
Jan Winkelmann committed
96
			res.SetError(err, cmdkit.ErrNormal)
97 98
			return
		}
99 100

		if !nd.OnlineMode() {
Jan Winkelmann's avatar
Jan Winkelmann committed
101
			res.SetError(errNotOnline, cmdkit.ErrClient)
102 103 104
			return
		}

105 106
		bs, ok := nd.Exchange.(*bitswap.Bitswap)
		if !ok {
Jan Winkelmann's avatar
Jan Winkelmann committed
107
			res.SetError(e.TypeErr(bs, nd.Exchange), cmdkit.ErrNormal)
108 109
			return
		}
110

111 112
		pstr, found, err := req.Option("peer").String()
		if err != nil {
Jan Winkelmann's avatar
Jan Winkelmann committed
113
			res.SetError(err, cmdkit.ErrNormal)
114 115 116 117 118
			return
		}
		if found {
			pid, err := peer.IDB58Decode(pstr)
			if err != nil {
Jan Winkelmann's avatar
Jan Winkelmann committed
119
				res.SetError(err, cmdkit.ErrNormal)
120 121
				return
			}
Jeromy's avatar
Jeromy committed
122 123 124 125 126
			if pid == nd.Identity {
				res.SetOutput(&KeyList{bs.GetWantlist()})
				return
			}

127 128 129 130
			res.SetOutput(&KeyList{bs.WantlistForPeer(pid)})
		} else {
			res.SetOutput(&KeyList{bs.GetWantlist()})
		}
131
	},
Jan Winkelmann's avatar
Jan Winkelmann committed
132 133
	Marshalers: oldcmds.MarshalerMap{
		oldcmds.Text: KeyListTextMarshaler,
134 135 136 137
	},
}

var bitswapStatCmd = &cmds.Command{
Jan Winkelmann's avatar
Jan Winkelmann committed
138
	Helptext: cmdkit.HelpText{
Richard Littauer's avatar
Richard Littauer committed
139
		Tagline:          "Show some diagnostic information on the bitswap agent.",
140 141 142
		ShortDescription: ``,
	},
	Type: bitswap.Stat{},
Jan Winkelmann's avatar
Jan Winkelmann committed
143
	Run: func(req cmds.Request, res cmds.ResponseEmitter) {
Jeromy's avatar
Jeromy committed
144
		nd, err := req.InvocContext().GetNode()
145
		if err != nil {
Jan Winkelmann's avatar
Jan Winkelmann committed
146
			res.SetError(err, cmdkit.ErrNormal)
147 148 149
			return
		}

150
		if !nd.OnlineMode() {
Jan Winkelmann's avatar
Jan Winkelmann committed
151
			res.SetError(errNotOnline, cmdkit.ErrClient)
152 153 154
			return
		}

155 156
		bs, ok := nd.Exchange.(*bitswap.Bitswap)
		if !ok {
Jan Winkelmann's avatar
Jan Winkelmann committed
157
			res.SetError(e.TypeErr(bs, nd.Exchange), cmdkit.ErrNormal)
158 159 160 161 162
			return
		}

		st, err := bs.Stat()
		if err != nil {
Jan Winkelmann's avatar
Jan Winkelmann committed
163
			res.SetError(err, cmdkit.ErrNormal)
164 165 166
			return
		}

keks's avatar
keks committed
167
		cmds.EmitOnce(res, st)
168
	},
Jan Winkelmann's avatar
Jan Winkelmann committed
169 170 171
	Encoders: cmds.EncoderMap{
		cmds.Text: cmds.MakeEncoder(func(req cmds.Request, w io.Writer, v interface{}) error {
			out, ok := v.(*bitswap.Stat)
172
			if !ok {
Jan Winkelmann's avatar
Jan Winkelmann committed
173
				return e.TypeErr(out, v)
174
			}
Jan Winkelmann's avatar
Jan Winkelmann committed
175 176 177 178 179 180 181 182 183 184

			fmt.Fprintln(w, "bitswap status")
			fmt.Fprintf(w, "\tprovides buffer: %d / %d\n", out.ProvideBufLen, bitswap.HasBlockBufferSize)
			fmt.Fprintf(w, "\tblocks received: %d\n", out.BlocksReceived)
			fmt.Fprintf(w, "\tblocks sent: %d\n", out.BlocksSent)
			fmt.Fprintf(w, "\tdata received: %d\n", out.DataReceived)
			fmt.Fprintf(w, "\tdata sent: %d\n", out.DataSent)
			fmt.Fprintf(w, "\tdup blocks received: %d\n", out.DupBlksReceived)
			fmt.Fprintf(w, "\tdup data received: %s\n", humanize.Bytes(out.DupDataReceived))
			fmt.Fprintf(w, "\twantlist [%d keys]\n", len(out.Wantlist))
Jeromy's avatar
Jeromy committed
185
			for _, k := range out.Wantlist {
Jan Winkelmann's avatar
Jan Winkelmann committed
186
				fmt.Fprintf(w, "\t\t%s\n", k.String())
Jeromy's avatar
Jeromy committed
187
			}
Jan Winkelmann's avatar
Jan Winkelmann committed
188
			fmt.Fprintf(w, "\tpartners [%d]\n", len(out.Peers))
Jeromy's avatar
Jeromy committed
189
			for _, p := range out.Peers {
Jan Winkelmann's avatar
Jan Winkelmann committed
190
				fmt.Fprintf(w, "\t\t%s\n", p)
191
			}
Jan Winkelmann's avatar
Jan Winkelmann committed
192 193 194

			return nil
		}),
195 196
	},
}
197

Jan Winkelmann's avatar
Jan Winkelmann committed
198 199
var ledgerCmd = &oldcmds.Command{
	Helptext: cmdkit.HelpText{
200 201 202 203 204 205 206
		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
207 208
	Arguments: []cmdkit.Argument{
		cmdkit.StringArg("peer", true, false, "The PeerID (B58) of the ledger to inspect."),
209 210
	},
	Type: decision.Receipt{},
Jan Winkelmann's avatar
Jan Winkelmann committed
211
	Run: func(req oldcmds.Request, res oldcmds.Response) {
212 213
		nd, err := req.InvocContext().GetNode()
		if err != nil {
Jan Winkelmann's avatar
Jan Winkelmann committed
214
			res.SetError(err, cmdkit.ErrNormal)
215 216 217 218
			return
		}

		if !nd.OnlineMode() {
Jan Winkelmann's avatar
Jan Winkelmann committed
219
			res.SetError(errNotOnline, cmdkit.ErrClient)
220 221 222 223 224
			return
		}

		bs, ok := nd.Exchange.(*bitswap.Bitswap)
		if !ok {
Jan Winkelmann's avatar
Jan Winkelmann committed
225
			res.SetError(e.TypeErr(bs, nd.Exchange), cmdkit.ErrNormal)
226 227 228 229 230
			return
		}

		partner, err := peer.IDB58Decode(req.Arguments()[0])
		if err != nil {
Jan Winkelmann's avatar
Jan Winkelmann committed
231
			res.SetError(err, cmdkit.ErrClient)
232 233 234 235
			return
		}
		res.SetOutput(bs.LedgerForPeer(partner))
	},
Jan Winkelmann's avatar
Jan Winkelmann committed
236 237 238 239 240 241 242 243
	Marshalers: oldcmds.MarshalerMap{
		oldcmds.Text: func(res oldcmds.Response) (io.Reader, error) {
			v, err := unwrapOutput(res.Output())
			if err != nil {
				return nil, err
			}

			out, ok := v.(*decision.Receipt)
244
			if !ok {
Jan Winkelmann's avatar
Jan Winkelmann committed
245
				return nil, e.TypeErr(out, v)
246
			}
Jan Winkelmann's avatar
Jan Winkelmann committed
247

248 249 250 251 252 253 254 255 256 257 258 259
			buf := new(bytes.Buffer)
			fmt.Fprintf(buf, "Ledger for %s\n"+
				"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)
			return buf, nil
		},
	},
}
260

Jan Winkelmann's avatar
Jan Winkelmann committed
261 262
var reprovideCmd = &oldcmds.Command{
	Helptext: cmdkit.HelpText{
263 264 265 266 267
		Tagline: "Trigger reprovider.",
		ShortDescription: `
Trigger reprovider to announce our data to network.
`,
	},
Jan Winkelmann's avatar
Jan Winkelmann committed
268
	Run: func(req oldcmds.Request, res oldcmds.Response) {
269 270
		nd, err := req.InvocContext().GetNode()
		if err != nil {
Jan Winkelmann's avatar
Jan Winkelmann committed
271
			res.SetError(err, cmdkit.ErrNormal)
272 273 274 275
			return
		}

		if !nd.OnlineMode() {
Jan Winkelmann's avatar
Jan Winkelmann committed
276
			res.SetError(errNotOnline, cmdkit.ErrClient)
277 278 279 280 281
			return
		}

		err = nd.Reprovider.Trigger(req.Context())
		if err != nil {
Jan Winkelmann's avatar
Jan Winkelmann committed
282
			res.SetError(err, cmdkit.ErrNormal)
283 284
			return
		}
Jan Winkelmann's avatar
Jan Winkelmann committed
285 286

		res.SetOutput(nil)
287 288
	},
}