github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/diagnostics/vis.go (about) 1 package diagnostics 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io" 7 8 peer "github.com/ipfs/go-ipfs/p2p/peer" 9 rtable "github.com/ipfs/go-ipfs/routing/kbucket" 10 ) 11 12 type node struct { 13 Name string `json:"name"` 14 Value uint64 `json:"value"` 15 RtKey string `json:"rtkey"` 16 } 17 18 type link struct { 19 Source int `json:"source"` 20 Target int `json:"target"` 21 Value int `json:"value"` 22 } 23 24 func GetGraphJson(dinfo []*DiagInfo) []byte { 25 out := make(map[string]interface{}) 26 names := make(map[string]int) 27 var nodes []*node 28 for _, di := range dinfo { 29 names[di.ID] = len(nodes) 30 val := di.BwIn + di.BwOut + 10 31 // include the routing table key, for proper routing table display 32 rtk := peer.ID(rtable.ConvertPeerID(peer.ID(di.ID))).Pretty() 33 nodes = append(nodes, &node{Name: di.ID, Value: val, RtKey: rtk}) 34 } 35 36 var links []*link 37 linkexists := make([][]bool, len(nodes)) 38 for i := range linkexists { 39 linkexists[i] = make([]bool, len(nodes)) 40 } 41 42 for _, di := range dinfo { 43 myid := names[di.ID] 44 for _, con := range di.Connections { 45 thisid := names[con.ID] 46 if !linkexists[thisid][myid] { 47 links = append(links, &link{ 48 Source: myid, 49 Target: thisid, 50 Value: 3, 51 }) 52 linkexists[myid][thisid] = true 53 } 54 } 55 } 56 57 out["nodes"] = nodes 58 out["links"] = links 59 60 b, err := json.Marshal(out) 61 if err != nil { 62 panic(err) 63 } 64 65 return b 66 } 67 68 type DotWriter struct { 69 W io.Writer 70 err error 71 } 72 73 // Write writes a buffer to the internal writer. 74 // It handles errors as in: http://blog.golang.org/errors-are-values 75 func (w *DotWriter) Write(buf []byte) (n int, err error) { 76 if w.err == nil { 77 n, w.err = w.W.Write(buf) 78 } 79 return n, w.err 80 } 81 82 // WriteS writes a string 83 func (w *DotWriter) WriteS(s string) (n int, err error) { 84 return w.Write([]byte(s)) 85 } 86 87 func (w *DotWriter) WriteNetHeader(dinfo []*DiagInfo) error { 88 label := fmt.Sprintf("Nodes: %d\\l", len(dinfo)) 89 90 w.WriteS("subgraph cluster_L { ") 91 w.WriteS("L [shape=box fontsize=32 label=\"" + label + "\"] ") 92 w.WriteS("}\n") 93 return w.err 94 } 95 96 func (w *DotWriter) WriteNode(i int, di *DiagInfo) error { 97 box := "[label=\"%s\n%d conns\" fontsize=8 shape=box tooltip=\"%s (%d conns)\"]" 98 box = fmt.Sprintf(box, di.ID, len(di.Connections), di.ID, len(di.Connections)) 99 100 w.WriteS(fmt.Sprintf("N%d %s\n", i, box)) 101 return w.err 102 } 103 104 func (w *DotWriter) WriteEdge(i, j int, di *DiagInfo, conn connDiagInfo) error { 105 106 n := fmt.Sprintf("%s ... %s (%d)", di.ID, conn.ID, conn.Latency) 107 s := "[label=\" %d\" weight=%d tooltip=\"%s\" labeltooltip=\"%s\" style=\"dotted\"]" 108 s = fmt.Sprintf(s, conn.Latency, conn.Count, n, n) 109 110 w.WriteS(fmt.Sprintf("N%d -> N%d %s\n", i, j, s)) 111 return w.err 112 } 113 114 func (w *DotWriter) WriteGraph(dinfo []*DiagInfo) error { 115 w.WriteS("digraph \"diag-net\" {\n") 116 w.WriteNetHeader(dinfo) 117 118 idx := make(map[string]int) 119 for i, di := range dinfo { 120 if _, found := idx[di.ID]; found { 121 log.Debugf("DotWriter skipped duplicate %s", di.ID) 122 continue 123 } 124 125 idx[di.ID] = i 126 w.WriteNode(i, di) 127 } 128 129 for i, di := range dinfo { 130 for _, conn := range di.Connections { 131 j, found := idx[conn.ID] 132 if !found { // if we didnt get it earlier... 133 j = len(idx) 134 idx[conn.ID] = j 135 } 136 137 w.WriteEdge(i, j, di, conn) 138 } 139 } 140 141 w.WriteS("}") 142 return w.err 143 }