mirror of
https://github.com/ipfs/kubo.git
synced 2025-09-10 09:52:20 +08:00
144 lines
3.2 KiB
Go
144 lines
3.2 KiB
Go
package diagnostics
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
|
|
rtable "github.com/ipfs/go-ipfs/routing/kbucket"
|
|
peer "gx/ipfs/QmccGfZs3rzku8Bv6sTPH3bMUKD1EVod8srgRjt5csdmva/go-libp2p/p2p/peer"
|
|
)
|
|
|
|
type node struct {
|
|
Name string `json:"name"`
|
|
Value uint64 `json:"value"`
|
|
RtKey string `json:"rtkey"`
|
|
}
|
|
|
|
type link struct {
|
|
Source int `json:"source"`
|
|
Target int `json:"target"`
|
|
Value int `json:"value"`
|
|
}
|
|
|
|
func GetGraphJson(dinfo []*DiagInfo) []byte {
|
|
out := make(map[string]interface{})
|
|
names := make(map[string]int)
|
|
var nodes []*node
|
|
for _, di := range dinfo {
|
|
names[di.ID] = len(nodes)
|
|
val := di.BwIn + di.BwOut + 10
|
|
// include the routing table key, for proper routing table display
|
|
rtk := peer.ID(rtable.ConvertPeerID(peer.ID(di.ID))).Pretty()
|
|
nodes = append(nodes, &node{Name: di.ID, Value: val, RtKey: rtk})
|
|
}
|
|
|
|
var links []*link
|
|
linkexists := make([][]bool, len(nodes))
|
|
for i := range linkexists {
|
|
linkexists[i] = make([]bool, len(nodes))
|
|
}
|
|
|
|
for _, di := range dinfo {
|
|
myid := names[di.ID]
|
|
for _, con := range di.Connections {
|
|
thisid := names[con.ID]
|
|
if !linkexists[thisid][myid] {
|
|
links = append(links, &link{
|
|
Source: myid,
|
|
Target: thisid,
|
|
Value: 3,
|
|
})
|
|
linkexists[myid][thisid] = true
|
|
}
|
|
}
|
|
}
|
|
|
|
out["nodes"] = nodes
|
|
out["links"] = links
|
|
|
|
b, err := json.Marshal(out)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return b
|
|
}
|
|
|
|
type DotWriter struct {
|
|
W io.Writer
|
|
err error
|
|
}
|
|
|
|
// Write writes a buffer to the internal writer.
|
|
// It handles errors as in: http://blog.golang.org/errors-are-values
|
|
func (w *DotWriter) Write(buf []byte) (n int, err error) {
|
|
if w.err == nil {
|
|
n, w.err = w.W.Write(buf)
|
|
}
|
|
return n, w.err
|
|
}
|
|
|
|
// WriteS writes a string
|
|
func (w *DotWriter) WriteS(s string) (n int, err error) {
|
|
return w.Write([]byte(s))
|
|
}
|
|
|
|
func (w *DotWriter) WriteNetHeader(dinfo []*DiagInfo) error {
|
|
label := fmt.Sprintf("Nodes: %d\\l", len(dinfo))
|
|
|
|
w.WriteS("subgraph cluster_L { ")
|
|
w.WriteS("L [shape=box fontsize=32 label=\"" + label + "\"] ")
|
|
w.WriteS("}\n")
|
|
return w.err
|
|
}
|
|
|
|
func (w *DotWriter) WriteNode(i int, di *DiagInfo) error {
|
|
box := "[label=\"%s\n%d conns\" fontsize=8 shape=box tooltip=\"%s (%d conns)\"]"
|
|
box = fmt.Sprintf(box, di.ID, len(di.Connections), di.ID, len(di.Connections))
|
|
|
|
w.WriteS(fmt.Sprintf("N%d %s\n", i, box))
|
|
return w.err
|
|
}
|
|
|
|
func (w *DotWriter) WriteEdge(i, j int, di *DiagInfo, conn connDiagInfo) error {
|
|
|
|
n := fmt.Sprintf("%s ... %s (%d)", di.ID, conn.ID, conn.Latency)
|
|
s := "[label=\" %d\" weight=%d tooltip=\"%s\" labeltooltip=\"%s\" style=\"dotted\"]"
|
|
s = fmt.Sprintf(s, conn.Latency, conn.Count, n, n)
|
|
|
|
w.WriteS(fmt.Sprintf("N%d -> N%d %s\n", i, j, s))
|
|
return w.err
|
|
}
|
|
|
|
func (w *DotWriter) WriteGraph(dinfo []*DiagInfo) error {
|
|
w.WriteS("digraph \"diag-net\" {\n")
|
|
w.WriteNetHeader(dinfo)
|
|
|
|
idx := make(map[string]int)
|
|
for i, di := range dinfo {
|
|
if _, found := idx[di.ID]; found {
|
|
log.Debugf("DotWriter skipped duplicate %s", di.ID)
|
|
continue
|
|
}
|
|
|
|
idx[di.ID] = i
|
|
w.WriteNode(i, di)
|
|
}
|
|
|
|
for i, di := range dinfo {
|
|
for _, conn := range di.Connections {
|
|
j, found := idx[conn.ID]
|
|
if !found { // if we didnt get it earlier...
|
|
j = len(idx)
|
|
idx[conn.ID] = j
|
|
}
|
|
|
|
w.WriteEdge(i, j, di, conn)
|
|
}
|
|
}
|
|
|
|
w.WriteS("}")
|
|
return w.err
|
|
}
|