bitswap.go 6.1 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"
10
	cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
Jan Winkelmann's avatar
Jan Winkelmann committed
11
	e "github.com/ipfs/go-ipfs/core/commands/e"
Steven Allen's avatar
Steven Allen committed
12 13
	bitswap "gx/ipfs/QmXBT58TaD2CJThpHy4xkxC1xsW4hXWBGZuKMepwjuzJ5B/go-bitswap"
	decision "gx/ipfs/QmXBT58TaD2CJThpHy4xkxC1xsW4hXWBGZuKMepwjuzJ5B/go-bitswap/decision"
14 15

	"gx/ipfs/QmPSBJL4momYnE7DcUyk2DVhD6rH488ZmHBGLbxNdhU44K/go-humanize"
16
	cmdkit "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
Steven Allen's avatar
Steven Allen committed
17 18
	cmds "gx/ipfs/QmXTmUCBtDUrzDYVzASogLiNph7EBuYqEgPL7QoHNMzUnz/go-ipfs-cmds"
	peer "gx/ipfs/QmbNepETomvmXfz1X5pHNFD2QuPqnqi47dTd94QJWSorQ3/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
		"stat":      bitswapStatCmd,
		"wantlist":  lgc.NewCommand(showWantlistCmd),
		"ledger":    lgc.NewCommand(ledgerCmd),
		"reprovide": lgc.NewCommand(reprovideCmd),
32 33 34
	},
}

Kejie Zhang's avatar
Kejie Zhang committed
35 36 37 38
const (
	peerOptionName = "peer"
)

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

		if !nd.OnlineMode() {
57
			res.SetError(ErrNotOnline, cmdkit.ErrClient)
58 59 60
			return
		}

61 62
		bs, ok := nd.Exchange.(*bitswap.Bitswap)
		if !ok {
Jan Winkelmann's avatar
Jan Winkelmann committed
63
			res.SetError(e.TypeErr(bs, nd.Exchange), cmdkit.ErrNormal)
64 65
			return
		}
66

Kejie Zhang's avatar
Kejie Zhang committed
67
		pstr, found, err := req.Option(peerOptionName).String()
68
		if err != nil {
Jan Winkelmann's avatar
Jan Winkelmann committed
69
			res.SetError(err, cmdkit.ErrNormal)
70 71 72 73 74
			return
		}
		if found {
			pid, err := peer.IDB58Decode(pstr)
			if err != nil {
Jan Winkelmann's avatar
Jan Winkelmann committed
75
				res.SetError(err, cmdkit.ErrNormal)
76 77
				return
			}
Jeromy's avatar
Jeromy committed
78 79 80 81 82
			if pid == nd.Identity {
				res.SetOutput(&KeyList{bs.GetWantlist()})
				return
			}

83 84 85 86
			res.SetOutput(&KeyList{bs.WantlistForPeer(pid)})
		} else {
			res.SetOutput(&KeyList{bs.GetWantlist()})
		}
87
	},
Jan Winkelmann's avatar
Jan Winkelmann committed
88 89
	Marshalers: oldcmds.MarshalerMap{
		oldcmds.Text: KeyListTextMarshaler,
90 91 92 93
	},
}

var bitswapStatCmd = &cmds.Command{
Jan Winkelmann's avatar
Jan Winkelmann committed
94
	Helptext: cmdkit.HelpText{
Richard Littauer's avatar
Richard Littauer committed
95
		Tagline:          "Show some diagnostic information on the bitswap agent.",
96 97 98
		ShortDescription: ``,
	},
	Type: bitswap.Stat{},
keks's avatar
keks committed
99
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
100
		nd, err := cmdenv.GetNode(env)
101
		if err != nil {
keks's avatar
keks committed
102
			return err
103 104
		}

105
		if !nd.OnlineMode() {
keks's avatar
keks committed
106
			return cmdkit.Errorf(cmdkit.ErrClient, ErrNotOnline.Error())
107 108
		}

109 110
		bs, ok := nd.Exchange.(*bitswap.Bitswap)
		if !ok {
keks's avatar
keks committed
111
			return e.TypeErr(bs, nd.Exchange)
112 113 114 115
		}

		st, err := bs.Stat()
		if err != nil {
keks's avatar
keks committed
116
			return err
117 118
		}

keks's avatar
keks committed
119
		return cmds.EmitOnce(res, st)
120
	},
Jan Winkelmann's avatar
Jan Winkelmann committed
121
	Encoders: cmds.EncoderMap{
122
		cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
Jan Winkelmann's avatar
Jan Winkelmann committed
123
			out, ok := v.(*bitswap.Stat)
124
			if !ok {
Jan Winkelmann's avatar
Jan Winkelmann committed
125
				return e.TypeErr(out, v)
126
			}
Jan Winkelmann's avatar
Jan Winkelmann committed
127 128 129 130 131 132 133 134 135 136

			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
137
			for _, k := range out.Wantlist {
Jan Winkelmann's avatar
Jan Winkelmann committed
138
				fmt.Fprintf(w, "\t\t%s\n", k.String())
Jeromy's avatar
Jeromy committed
139
			}
Jan Winkelmann's avatar
Jan Winkelmann committed
140
			fmt.Fprintf(w, "\tpartners [%d]\n", len(out.Peers))
Jeromy's avatar
Jeromy committed
141
			for _, p := range out.Peers {
Jan Winkelmann's avatar
Jan Winkelmann committed
142
				fmt.Fprintf(w, "\t\t%s\n", p)
143
			}
Jan Winkelmann's avatar
Jan Winkelmann committed
144 145 146

			return nil
		}),
147 148
	},
}
149

Jan Winkelmann's avatar
Jan Winkelmann committed
150 151
var ledgerCmd = &oldcmds.Command{
	Helptext: cmdkit.HelpText{
152 153 154 155 156 157 158
		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
159 160
	Arguments: []cmdkit.Argument{
		cmdkit.StringArg("peer", true, false, "The PeerID (B58) of the ledger to inspect."),
161 162
	},
	Type: decision.Receipt{},
Jan Winkelmann's avatar
Jan Winkelmann committed
163
	Run: func(req oldcmds.Request, res oldcmds.Response) {
164 165
		nd, err := req.InvocContext().GetNode()
		if err != nil {
Jan Winkelmann's avatar
Jan Winkelmann committed
166
			res.SetError(err, cmdkit.ErrNormal)
167 168 169 170
			return
		}

		if !nd.OnlineMode() {
171
			res.SetError(ErrNotOnline, cmdkit.ErrClient)
172 173 174 175 176
			return
		}

		bs, ok := nd.Exchange.(*bitswap.Bitswap)
		if !ok {
Jan Winkelmann's avatar
Jan Winkelmann committed
177
			res.SetError(e.TypeErr(bs, nd.Exchange), cmdkit.ErrNormal)
178 179 180 181 182
			return
		}

		partner, err := peer.IDB58Decode(req.Arguments()[0])
		if err != nil {
Jan Winkelmann's avatar
Jan Winkelmann committed
183
			res.SetError(err, cmdkit.ErrClient)
184 185 186 187
			return
		}
		res.SetOutput(bs.LedgerForPeer(partner))
	},
Jan Winkelmann's avatar
Jan Winkelmann committed
188 189 190 191 192 193 194 195
	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)
196
			if !ok {
Jan Winkelmann's avatar
Jan Winkelmann committed
197
				return nil, e.TypeErr(out, v)
198
			}
Jan Winkelmann's avatar
Jan Winkelmann committed
199

200 201 202 203 204 205 206 207 208 209 210 211
			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
		},
	},
}
212

Jan Winkelmann's avatar
Jan Winkelmann committed
213 214
var reprovideCmd = &oldcmds.Command{
	Helptext: cmdkit.HelpText{
215 216 217 218 219
		Tagline: "Trigger reprovider.",
		ShortDescription: `
Trigger reprovider to announce our data to network.
`,
	},
Jan Winkelmann's avatar
Jan Winkelmann committed
220
	Run: func(req oldcmds.Request, res oldcmds.Response) {
221 222
		nd, err := req.InvocContext().GetNode()
		if err != nil {
Jan Winkelmann's avatar
Jan Winkelmann committed
223
			res.SetError(err, cmdkit.ErrNormal)
224 225 226 227
			return
		}

		if !nd.OnlineMode() {
228
			res.SetError(ErrNotOnline, cmdkit.ErrClient)
229 230 231 232 233
			return
		}

		err = nd.Reprovider.Trigger(req.Context())
		if err != nil {
Jan Winkelmann's avatar
Jan Winkelmann committed
234
			res.SetError(err, cmdkit.ErrNormal)
235 236
			return
		}
Jan Winkelmann's avatar
Jan Winkelmann committed
237 238

		res.SetOutput(nil)
239 240
	},
}