mirror of
https://github.com/anyproto/any-sync.git
synced 2025-06-11 18:20:28 +09:00
162 lines
3.4 KiB
Go
162 lines
3.4 KiB
Go
//go:build (linux || darwin) && !android && !ios && !nographviz && (amd64 || arm64)
|
|
// +build linux darwin
|
|
// +build !android
|
|
// +build !ios
|
|
// +build !nographviz
|
|
// +build amd64 arm64
|
|
|
|
package threadbuilder
|
|
|
|
import (
|
|
"fmt"
|
|
testpb "github.com/anytypeio/go-anytype-infrastructure-experiments/acl/testutils/testchanges/pb"
|
|
|
|
"github.com/gogo/protobuf/proto"
|
|
"strings"
|
|
"unicode"
|
|
|
|
"github.com/awalterschulze/gographviz"
|
|
)
|
|
|
|
// To quickly look at visualized string you can use https://dreampuf.github.io/GraphvizOnline
|
|
|
|
type EdgeParameters struct {
|
|
style string
|
|
color string
|
|
label string
|
|
}
|
|
|
|
func (t *ThreadBuilder) Graph() (string, error) {
|
|
// TODO: check updates on https://github.com/goccy/go-graphviz/issues/52 or make a fix yourself to use better library here
|
|
graph := gographviz.NewGraph()
|
|
graph.SetName("G")
|
|
graph.SetDir(true)
|
|
var nodes = make(map[string]struct{})
|
|
|
|
var addNodes = func(r *threadChange) error {
|
|
// TODO: revisit function after checking
|
|
|
|
style := "solid"
|
|
if r.GetAclData() != nil {
|
|
style = "filled"
|
|
} else if r.changesDataDecrypted != nil {
|
|
style = "dashed"
|
|
}
|
|
|
|
var chSymbs []string
|
|
if r.changesDataDecrypted != nil {
|
|
res := &testpb.PlainTextChangeData{}
|
|
err := proto.Unmarshal(r.changesDataDecrypted, res)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, chc := range res.Content {
|
|
tp := fmt.Sprintf("%T", chc.Value)
|
|
tp = strings.Replace(tp, "ChangeContentValueOf", "", 1)
|
|
res := ""
|
|
for _, ts := range tp {
|
|
if unicode.IsUpper(ts) {
|
|
res += string(ts)
|
|
}
|
|
}
|
|
chSymbs = append(chSymbs, res)
|
|
}
|
|
}
|
|
if r.GetAclData() != nil {
|
|
for _, chc := range r.GetAclData().AclContent {
|
|
tp := fmt.Sprintf("%T", chc.Value)
|
|
tp = strings.Replace(tp, "ACLChangeACLContentValueValueOf", "", 1)
|
|
res := ""
|
|
for _, ts := range tp {
|
|
if unicode.IsUpper(ts) {
|
|
res += string(ts)
|
|
}
|
|
}
|
|
chSymbs = append(chSymbs, res)
|
|
}
|
|
}
|
|
|
|
shortId := r.id
|
|
label := fmt.Sprintf("Id: %s\nChanges: %s\n",
|
|
shortId,
|
|
strings.Join(chSymbs, ","),
|
|
)
|
|
e := graph.AddNode("G", "\""+r.id+"\"", map[string]string{
|
|
"label": "\"" + label + "\"",
|
|
"style": "\"" + style + "\"",
|
|
})
|
|
if e != nil {
|
|
return e
|
|
}
|
|
nodes[r.id] = struct{}{}
|
|
return nil
|
|
}
|
|
|
|
var createEdge = func(firstId, secondId string, params EdgeParameters) error {
|
|
_, exists := nodes[firstId]
|
|
if !exists {
|
|
return fmt.Errorf("no such node")
|
|
}
|
|
_, exists = nodes[secondId]
|
|
if !exists {
|
|
return fmt.Errorf("no previous node")
|
|
}
|
|
|
|
err := graph.AddEdge("\""+firstId+"\"", "\""+secondId+"\"", true, map[string]string{
|
|
"color": params.color,
|
|
"style": params.style,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
var addLinks = func(t *threadChange) error {
|
|
for _, prevId := range t.AclHeadIds {
|
|
err := createEdge(t.id, prevId, EdgeParameters{
|
|
style: "dashed",
|
|
color: "red",
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
for _, prevId := range t.TreeHeadIds {
|
|
err := createEdge(t.id, prevId, EdgeParameters{
|
|
style: "dashed",
|
|
color: "blue",
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if t.SnapshotBaseId != "" {
|
|
err := createEdge(t.id, t.SnapshotBaseId, EdgeParameters{
|
|
style: "bold",
|
|
color: "blue",
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
err := t.traverseFromHeads(addNodes)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
err = t.traverseFromHeads(addLinks)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return graph.String(), nil
|
|
}
|