mirror of
https://github.com/ipfs/kubo.git
synced 2025-06-04 21:39:39 +08:00
183 lines
4.2 KiB
Go
183 lines
4.2 KiB
Go
package commands
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"time"
|
|
|
|
humanize "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/dustin/go-humanize"
|
|
|
|
cmds "github.com/ipfs/go-ipfs/commands"
|
|
metrics "github.com/ipfs/go-ipfs/metrics"
|
|
peer "github.com/ipfs/go-ipfs/p2p/peer"
|
|
protocol "github.com/ipfs/go-ipfs/p2p/protocol"
|
|
u "github.com/ipfs/go-ipfs/util"
|
|
)
|
|
|
|
var StatsCmd = &cmds.Command{
|
|
Helptext: cmds.HelpText{
|
|
Tagline: "Query IPFS statistics",
|
|
ShortDescription: ``,
|
|
},
|
|
|
|
Subcommands: map[string]*cmds.Command{
|
|
"bw": statBwCmd,
|
|
},
|
|
}
|
|
|
|
var statBwCmd = &cmds.Command{
|
|
Helptext: cmds.HelpText{
|
|
Tagline: "Print ipfs bandwidth information",
|
|
ShortDescription: ``,
|
|
},
|
|
Options: []cmds.Option{
|
|
cmds.StringOption("peer", "p", "specify a peer to print bandwidth for"),
|
|
cmds.StringOption("proto", "t", "specify a protocol to print bandwidth for"),
|
|
cmds.BoolOption("poll", "print bandwidth at an interval"),
|
|
cmds.StringOption("interval", "i", "time interval to wait between updating output"),
|
|
},
|
|
|
|
Run: func(req cmds.Request, res cmds.Response) {
|
|
nd, err := req.InvocContext().GetNode()
|
|
if err != nil {
|
|
res.SetError(err, cmds.ErrNormal)
|
|
return
|
|
}
|
|
|
|
// Must be online!
|
|
if !nd.OnlineMode() {
|
|
res.SetError(errNotOnline, cmds.ErrClient)
|
|
return
|
|
}
|
|
|
|
pstr, pfound, err := req.Option("peer").String()
|
|
if err != nil {
|
|
res.SetError(err, cmds.ErrNormal)
|
|
return
|
|
}
|
|
|
|
tstr, tfound, err := req.Option("proto").String()
|
|
if err != nil {
|
|
res.SetError(err, cmds.ErrNormal)
|
|
return
|
|
}
|
|
if pfound && tfound {
|
|
res.SetError(errors.New("please only specify peer OR protocol"), cmds.ErrClient)
|
|
return
|
|
}
|
|
|
|
var pid peer.ID
|
|
if pfound {
|
|
checkpid, err := peer.IDB58Decode(pstr)
|
|
if err != nil {
|
|
res.SetError(err, cmds.ErrNormal)
|
|
return
|
|
}
|
|
pid = checkpid
|
|
}
|
|
|
|
interval := time.Second
|
|
timeS, found, err := req.Option("interval").String()
|
|
if err != nil {
|
|
res.SetError(err, cmds.ErrNormal)
|
|
return
|
|
}
|
|
if found {
|
|
v, err := time.ParseDuration(timeS)
|
|
if err != nil {
|
|
res.SetError(err, cmds.ErrNormal)
|
|
return
|
|
}
|
|
interval = v
|
|
}
|
|
|
|
doPoll, _, err := req.Option("poll").Bool()
|
|
if err != nil {
|
|
res.SetError(err, cmds.ErrNormal)
|
|
return
|
|
}
|
|
|
|
out := make(chan interface{})
|
|
res.SetOutput((<-chan interface{})(out))
|
|
|
|
go func() {
|
|
defer close(out)
|
|
for {
|
|
if pfound {
|
|
stats := nd.Reporter.GetBandwidthForPeer(pid)
|
|
out <- &stats
|
|
} else if tfound {
|
|
protoId := protocol.ID(tstr)
|
|
stats := nd.Reporter.GetBandwidthForProtocol(protoId)
|
|
out <- &stats
|
|
} else {
|
|
totals := nd.Reporter.GetBandwidthTotals()
|
|
out <- &totals
|
|
}
|
|
if !doPoll {
|
|
return
|
|
}
|
|
select {
|
|
case <-time.After(interval):
|
|
case <-req.Context().Done():
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
},
|
|
Type: metrics.Stats{},
|
|
Marshalers: cmds.MarshalerMap{
|
|
cmds.Text: func(res cmds.Response) (io.Reader, error) {
|
|
outCh, ok := res.Output().(<-chan interface{})
|
|
if !ok {
|
|
return nil, u.ErrCast()
|
|
}
|
|
|
|
polling, _, err := res.Request().Option("poll").Bool()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
first := true
|
|
marshal := func(v interface{}) (io.Reader, error) {
|
|
bs, ok := v.(*metrics.Stats)
|
|
if !ok {
|
|
return nil, u.ErrCast()
|
|
}
|
|
out := new(bytes.Buffer)
|
|
if !polling {
|
|
printStats(out, bs)
|
|
} else {
|
|
if first {
|
|
fmt.Fprintln(out, "Total Up\t Total Down\t Rate Up\t Rate Down")
|
|
first = false
|
|
}
|
|
fmt.Fprint(out, "\r")
|
|
fmt.Fprintf(out, "%s \t\t", humanize.Bytes(uint64(bs.TotalOut)))
|
|
fmt.Fprintf(out, " %s \t\t", humanize.Bytes(uint64(bs.TotalIn)))
|
|
fmt.Fprintf(out, " %s/s \t", humanize.Bytes(uint64(bs.RateOut)))
|
|
fmt.Fprintf(out, " %s/s ", humanize.Bytes(uint64(bs.RateIn)))
|
|
}
|
|
return out, nil
|
|
|
|
}
|
|
|
|
return &cmds.ChannelMarshaler{
|
|
Channel: outCh,
|
|
Marshaler: marshal,
|
|
Res: res,
|
|
}, nil
|
|
},
|
|
},
|
|
}
|
|
|
|
func printStats(out io.Writer, bs *metrics.Stats) {
|
|
fmt.Fprintln(out, "Bandwidth")
|
|
fmt.Fprintf(out, "TotalIn: %s\n", humanize.Bytes(uint64(bs.TotalIn)))
|
|
fmt.Fprintf(out, "TotalOut: %s\n", humanize.Bytes(uint64(bs.TotalOut)))
|
|
fmt.Fprintf(out, "RateIn: %s/s\n", humanize.Bytes(uint64(bs.RateIn)))
|
|
fmt.Fprintf(out, "RateOut: %s/s\n", humanize.Bytes(uint64(bs.RateOut)))
|
|
}
|