/
locationgraph.go
182 lines (155 loc) · 5.12 KB
/
locationgraph.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
package coreapi
import (
"encoding/json"
"fmt"
"io"
"strings"
"github.com/breiting/tree"
"github.com/roboticeyes/gorexos"
)
// LocationGraph contains everything for getting information about the location graph in REXos
type LocationGraph struct {
ProjectUrn string
ProjectType string
Tree *tree.Node
References []Reference
ProjectFiles []ProjectFile
}
// locationGraphHal is a serialized linked list of all references belonging to one project.
// this can be retrieved by /projects/:id/rexReferences?projection=linkedList
type locationGraphHal struct {
Embedded struct {
RexReferences []Reference `json:"rexReferences"`
} `json:"_embedded"`
Links struct {
Self struct {
Href string `json:"href"`
} `json:"self"`
} `json:"_links"`
}
// GetLocationGraphByProjectUrn returns the full location graph for the given project URN
func GetLocationGraphByProjectUrn(handler gorexos.RequestHandler, projectUrn string) (LocationGraph, error) {
var locTree LocationGraph
// Get project
project, err := GetProjectByUrn(handler, projectUrn)
if err != nil {
return locTree, err
}
locTree.ProjectUrn = project.Urn
locTree.ProjectType = project.Type
// Get project file list
locTree.ProjectFiles, err = GetProjectFilesByProjectSelfLink(handler, project.SelfLink)
// Get references
resp, err := handler.GetFullyQualified(project.SelfLink + "/rexReferences?projection=linkedList")
if err != nil {
return locTree, err
}
var halTree locationGraphHal
err = json.Unmarshal(resp.Body(), &halTree)
if err != nil {
return locTree, err
}
locTree.References = halTree.Embedded.RexReferences
locTree.Tree, err = reconstructLocationGraphfromJSON(halTree.Embedded.RexReferences)
return locTree, err
}
// GetTransformations fetches all transformations for all references and project files
func (t *LocationGraph) GetTransformations(handler gorexos.RequestHandler) error {
for i, ref := range t.References {
resp, err := handler.Get(apiReferences + "/" + StripPrefix(ref.Urn))
if err != nil {
return err
}
var refResponse Reference
err = json.Unmarshal(resp.Body(), &refResponse)
t.References[i].LocalTransformation = refResponse.LocalTransformation
t.References[i].WorldTransformation = refResponse.WorldTransformation
}
for i, projectFile := range t.ProjectFiles {
resp, err := handler.Get(apiProjectFiles + "/" + StripPrefix(projectFile.Urn))
if err != nil {
return err
}
var projectFileResponse ProjectFile
err = json.Unmarshal(resp.Body(), &projectFileResponse)
t.ProjectFiles[i].DataTransformation = projectFileResponse.DataTransformation
}
return nil
}
// Beautify modifies the tree and adds attributes to the graph
func (t *LocationGraph) Beautify() {
// add project node
root := tree.NewNode(t.ProjectType + "\n" + StripPrefix(t.ProjectUrn))
root.Attributes["shape"] = "octagon"
root.Attributes["color"] = "azure2"
root.Children = append(root.Children, t.Tree)
t.Tree = root
for _, v := range t.References {
node := tree.FindByID(t.Tree, StripPrefix(v.Urn))
if node != nil {
switch v.Type {
case "portal":
node.Attributes["color"] = "goldenrod1"
node.Attributes["shape"] = "circle"
case "root":
node.Attributes["shape"] = "doublecircle"
node.Attributes["color"] = "firebrick"
// case "group":
// see below with categories
// node.Attributes["color"] = "darkolivegreen1"
case "file":
node.Attributes["color"] = "dodgerblue3"
}
switch v.Category {
case "activity":
node.ID = "Activity\n" + node.ID
node.Attributes["color"] = "chocolate2"
case "inspection":
node.ID = "Inspection\n" + node.ID
node.Attributes["color"] = "seagreen1"
case "track":
node.ID = "Track\n" + node.ID
node.Attributes["color"] = "orchid3"
case "file":
node.ID = "File\n" + node.ID
case "route":
node.ID = "Route\n" + node.ID
node.Attributes["color"] = "hotpink4"
case "data":
node.ID = "Data\n" + node.ID
node.Attributes["color"] = "aquamarine4"
}
// attach project file
for _, p := range t.ProjectFiles {
if p.Urn == v.ProjectFileUrn {
// found project file
fileSize := fmt.Sprintf("~%.2fmb", float32(p.FileSize)/1000.0/1000.0)
pfNode := &tree.Node{
ID: p.Type + "\n" + StripPrefix(p.Urn) + "\n" + fileSize,
Name: p.Name,
Attributes: make(map[string]string),
}
pfNode.Attributes["shape"] = "box"
pfNode.Attributes["color"] = "powderblue"
node.Children = append(node.Children, pfNode)
}
}
}
}
}
// WriteToDot gets the location graph of the project and dumps out the structure as DOT file (graphviz)
func (t *LocationGraph) WriteToDot(w io.Writer) error {
return tree.WriteToDot(t.Tree, w)
}
func reconstructLocationGraphfromJSON(refs []Reference) (*tree.Node, error) {
var relations []tree.Relation
for _, v := range refs {
relations = append(relations, tree.Relation{ID: StripPrefix(v.Urn), ParentID: StripPrefix(v.ParentReferenceUrn)})
}
return tree.Deserialize(relations)
}
// StripPrefix removes the prefix of the URN and only returns the ID
func StripPrefix(urn string) string {
parts := strings.Split(urn, ":")
return parts[len(parts)-1]
}