Skip to content
File

Blob: chord/graph_handler.go

go104 lines
1package chord
2 
3import (
4 "fmt"
5 "net/http"
6 "strconv"
7 
8 "go.miragespace.co/specter/spec/chord"
9 "go.miragespace.co/specter/spec/protocol"
10 
11 "github.com/dominikbraun/graph"
12 "github.com/dominikbraun/graph/draw"
13)
14 
15func formatNode(n *protocol.Node) string {
16 return fmt.Sprintf("%s/%d", n.GetAddress(), n.GetId())
17}
18 
19var vOptions = []func(*graph.VertexProperties){
20 graph.VertexAttribute("shape", "box"),
21}
22 
23var rootVOptions = append(vOptions,
24 graph.VertexAttribute("style", "filled"),
25 graph.VertexAttribute("color", "yellow"),
26)
27 
28var selfVOptions = append(vOptions,
29 graph.VertexAttribute("style", "filled"),
30 graph.VertexAttribute("color", "lightgrey"),
31)
32 
33func ringGraphHandler(root *LocalNode) http.HandlerFunc {
34 return func(w http.ResponseWriter, r *http.Request) {
35 var err error
36 var next chord.VNode = root
37 
38 nodes := make([]*protocol.Node, 0)
39 seen := make(map[uint64]bool)
40 lookup := make(map[string]*protocol.Node)
41 
42 predecessor := root.getPredecessor()
43 if predecessor == nil {
44 http.Error(w, "predecessor is nil", 500)
45 return
46 }
47 
48 for {
49 next, err = root.FindSuccessor(chord.ModuloSum(next.ID(), 1))
50 if err != nil {
51 http.Error(w, err.Error(), 500)
52 return
53 }
54 if next == nil {
55 http.Error(w, "successor is nil", 500)
56 return
57 }
58 if next.ID() == root.ID() {
59 nodes = append(nodes, root.Identity())
60 break
61 }
62 if seen[next.ID()] {
63 http.Error(w, "ring is unstable", 500)
64 return
65 }
66 nodes = append(nodes, next.Identity())
67 seen[next.ID()] = true
68 }
69 
70 ring := graph.New(formatNode, graph.Directed())
71 
72 for _, node := range nodes {
73 if node.GetId() == root.ID() {
74 ring.AddVertex(node, rootVOptions...)
75 } else if node.GetAddress() == root.Identity().GetAddress() {
76 ring.AddVertex(node, selfVOptions...)
77 } else {
78 ring.AddVertex(node, vOptions...)
79 }
80 lookup[strconv.FormatUint(node.GetId(), 10)] = node
81 }
82 
83 ring.AddEdge(formatNode(root.Identity()), formatNode(predecessor.Identity()), graph.EdgeAttribute("color", "blue"))
84 for i := 0; i < len(nodes)-1; i++ {
85 ring.AddEdge(formatNode(nodes[i]), formatNode(nodes[i+1]), graph.EdgeAttribute("color", "red"))
86 }
87 ring.AddEdge(formatNode(nodes[len(nodes)-1]), formatNode(nodes[0]), graph.EdgeAttribute("color", "red"))
88 
89 fingers := root.fingerTrace()
90 for r, id := range fingers {
91 s := formatNode(root.Identity())
92 d := formatNode(lookup[id])
93 err := ring.AddEdge(s, d, graph.EdgeAttribute("label", r))
94 if err == graph.ErrEdgeAlreadyExists {
95 ring.RemoveEdge(s, d)
96 ring.AddEdge(s, d, graph.EdgeAttribute("label", r), graph.EdgeAttribute("color", "red"))
97 }
98 }
99 
100 w.Header().Set("content-type", "text/plain")
101 draw.DOT(ring, w)
102 }
103}