mirror of
https://github.com/ipfs/kubo.git
synced 2025-09-17 04:29:52 +08:00
130 lines
2.7 KiB
Go
130 lines
2.7 KiB
Go
package commands
|
|
|
|
import (
|
|
"bytes"
|
|
"io"
|
|
"text/template"
|
|
"time"
|
|
|
|
cmds "github.com/jbenet/go-ipfs/commands"
|
|
util "github.com/jbenet/go-ipfs/util"
|
|
)
|
|
|
|
type DiagnosticConnection struct {
|
|
ID string
|
|
// TODO use milliseconds or microseconds for human readability
|
|
NanosecondsLatency uint64
|
|
}
|
|
|
|
type DiagnosticPeer struct {
|
|
ID string
|
|
UptimeSeconds uint64
|
|
BandwidthBytesIn uint64
|
|
BandwidthBytesOut uint64
|
|
Connections []DiagnosticConnection
|
|
}
|
|
|
|
type DiagnosticOutput struct {
|
|
Peers []DiagnosticPeer
|
|
}
|
|
|
|
var DiagCmd = &cmds.Command{
|
|
Helptext: cmds.HelpText{
|
|
Tagline: "Generates diagnostic reports",
|
|
},
|
|
|
|
Subcommands: map[string]*cmds.Command{
|
|
"net": diagNetCmd,
|
|
},
|
|
}
|
|
|
|
var diagNetCmd = &cmds.Command{
|
|
Helptext: cmds.HelpText{
|
|
Tagline: "Generates a network diagnostics report",
|
|
ShortDescription: `
|
|
Sends out a message to each node in the network recursively
|
|
requesting a listing of data about them including number of
|
|
connected peers and latencies between them.
|
|
`,
|
|
},
|
|
|
|
Run: func(req cmds.Request) (interface{}, error) {
|
|
n, err := req.Context().GetNode()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if !n.OnlineMode() {
|
|
return nil, errNotOnline
|
|
}
|
|
|
|
info, err := n.Diagnostics.GetDiagnostic(time.Second * 20)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
output := make([]DiagnosticPeer, len(info))
|
|
for i, peer := range info {
|
|
connections := make([]DiagnosticConnection, len(peer.Connections))
|
|
for j, conn := range peer.Connections {
|
|
connections[j] = DiagnosticConnection{
|
|
ID: conn.ID,
|
|
NanosecondsLatency: uint64(conn.Latency.Nanoseconds()),
|
|
}
|
|
}
|
|
|
|
output[i] = DiagnosticPeer{
|
|
ID: peer.ID,
|
|
UptimeSeconds: uint64(peer.LifeSpan.Seconds()),
|
|
BandwidthBytesIn: peer.BwIn,
|
|
BandwidthBytesOut: peer.BwOut,
|
|
Connections: connections,
|
|
}
|
|
}
|
|
|
|
return &DiagnosticOutput{output}, nil
|
|
},
|
|
Type: &DiagnosticOutput{},
|
|
Marshalers: cmds.MarshalerMap{
|
|
cmds.Text: func(r cmds.Response) ([]byte, error) {
|
|
output, ok := r.Output().(*DiagnosticOutput)
|
|
if !ok {
|
|
return nil, util.ErrCast()
|
|
}
|
|
var buf bytes.Buffer
|
|
err := printDiagnostics(&buf, output)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return buf.Bytes(), nil
|
|
},
|
|
},
|
|
}
|
|
|
|
func printDiagnostics(out io.Writer, info *DiagnosticOutput) error {
|
|
|
|
diagTmpl := `
|
|
{{ range $peer := .Peers }}
|
|
ID {{ $peer.ID }}
|
|
up {{ $peer.UptimeSeconds }} seconds
|
|
connected to {{ len .Connections }}...
|
|
{{ range $connection := .Connections }}
|
|
ID {{ $connection.ID }}
|
|
latency: {{ $connection.NanosecondsLatency }} ns
|
|
{{ end }}
|
|
{{end}}
|
|
`
|
|
|
|
templ, err := template.New("DiagnosticOutput").Parse(diagTmpl)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = templ.Execute(out, info)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|