// Copyright (C) 2019 Storj Labs, Inc. // See LICENSE for copying information. package routinggraph import ( "fmt" "io" "storj.io/storj/pkg/pb" ) type dot struct { out io.Writer err error } func (dot *dot) printf(format string, args ...interface{}) { if dot.err != nil { return } _, dot.err = fmt.Fprintf(dot.out, format, args...) } // Draw writes the routing graph obtained using a GetBucketListResponse in the specified file func Draw(w io.Writer, info *pb.GetBucketListResponse) (err error) { dot := dot{out: w} dot.printf(`digraph{node [shape=plaintext, fontname="Courier"];edge [dir=none];`) defer dot.printf("}") buckets := info.GetBuckets() dot.addBuckets(buckets, 0, "") return dot.err } func (dot *dot) addBuckets(b []*pb.GetBucketListResponse_Bucket, depth int, inPrefix string) { if len(b) == 1 { dot.Leaf(b[0], inPrefix) return } left, right := splitBucket(b, depth) outPrefix := extendPrefix(inPrefix, false) dot.printf("b%s [shape=point];", inPrefix) dot.addBuckets(left, depth+1, outPrefix) dot.Edge(inPrefix, outPrefix, "0") outPrefix = extendPrefix(inPrefix, true) dot.addBuckets(right, depth+1, outPrefix) dot.Edge(inPrefix, outPrefix, "1") } func (dot *dot) Edge(inPrefix, outPrefix, label string) { dot.printf(`b%s -> b%s [label=<%s>];`, inPrefix, outPrefix, label) } func (dot *dot) Leaf(b *pb.GetBucketListResponse_Bucket, prefix string) { dot.printf(`b%s [label=<
%s |