bitswap.go 7.31 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
	oldcmds "github.com/ipfs/go-ipfs/commands"
9
	lgc "github.com/ipfs/go-ipfs/commands/legacy"
Jan Winkelmann's avatar
Jan Winkelmann committed
10
	e "github.com/ipfs/go-ipfs/core/commands/e"
Steven Allen's avatar
Steven Allen committed
11 12
	bitswap "gx/ipfs/QmNQQEYL3Vpj4beteqyeRpVpivuX1wBP6Q5GZMdBPPTV3S/go-bitswap"
	decision "gx/ipfs/QmNQQEYL3Vpj4beteqyeRpVpivuX1wBP6Q5GZMdBPPTV3S/go-bitswap/decision"
13 14

	"gx/ipfs/QmPSBJL4momYnE7DcUyk2DVhD6rH488ZmHBGLbxNdhU44K/go-humanize"
15 16
	cmdkit "gx/ipfs/QmPVqQHEfLpqK7JLCsUkyam7rhuV3MAeZ9gueQQCrBwCta/go-ipfs-cmdkit"
	cmds "gx/ipfs/QmUQb3xtNzkQCgTj2NjaqcJZNv2nfSSub2QAdy9DtQMRBT/go-ipfs-cmds"
Steven Allen's avatar
Steven Allen committed
17
	cid "gx/ipfs/QmYVNvtQkeZ6AKSwDrjQTs432QtL6umrrK41EBq3cu7iSP/go-cid"
Steven Allen's avatar
Steven Allen committed
18
	peer "gx/ipfs/QmcZSzKEM5yDfpZbeEEZaVmaZ1zXm6JWTbrQZSB8hCVPzk/go-libp2p-peer"
19 20 21
)

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

27
	Subcommands: map[string]*cmds.Command{
28 29 30 31 32
		"stat":      bitswapStatCmd,
		"wantlist":  lgc.NewCommand(showWantlistCmd),
		"unwant":    lgc.NewCommand(unwantCmd),
		"ledger":    lgc.NewCommand(ledgerCmd),
		"reprovide": lgc.NewCommand(reprovideCmd),
33 34 35
	},
}

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

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

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

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

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

Jeromy's avatar
Jeromy committed
72 73 74 75 76
		// 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
77 78

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

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

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

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

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

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

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

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

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

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

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

			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
184
			for _, k := range out.Wantlist {
Jan Winkelmann's avatar
Jan Winkelmann committed
185
				fmt.Fprintf(w, "\t\t%s\n", k.String())
Jeromy's avatar
Jeromy committed
186
			}
Jan Winkelmann's avatar
Jan Winkelmann committed
187
			fmt.Fprintf(w, "\tpartners [%d]\n", len(out.Peers))
Jeromy's avatar
Jeromy committed
188
			for _, p := range out.Peers {
Jan Winkelmann's avatar
Jan Winkelmann committed
189
				fmt.Fprintf(w, "\t\t%s\n", p)
190
			}
Jan Winkelmann's avatar
Jan Winkelmann committed
191 192 193

			return nil
		}),
194 195
	},
}
196

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

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

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

		partner, err := peer.IDB58Decode(req.Arguments()[0])
		if err != nil {
Jan Winkelmann's avatar
Jan Winkelmann committed
230
			res.SetError(err, cmdkit.ErrClient)
231 232 233 234
			return
		}
		res.SetOutput(bs.LedgerForPeer(partner))
	},
Jan Winkelmann's avatar
Jan Winkelmann committed
235 236 237 238 239 240 241 242
	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)
243
			if !ok {
Jan Winkelmann's avatar
Jan Winkelmann committed
244
				return nil, e.TypeErr(out, v)
245
			}
Jan Winkelmann's avatar
Jan Winkelmann committed
246

247 248 249 250 251 252 253 254 255 256 257 258
			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
		},
	},
}
259

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

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

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

		res.SetOutput(nil)
286 287
	},
}