1
0
forked from extern/smegmesh
smegmesh/pkg/automerge/automerge.go

143 lines
2.8 KiB
Go
Raw Normal View History

2023-10-05 18:48:54 +02:00
package crdt
2023-10-06 12:52:51 +02:00
import (
"net"
"strings"
2023-10-06 12:52:51 +02:00
"github.com/automerge/automerge-go"
logging "github.com/tim-beatham/wgmesh/pkg/log"
"golang.zx2c4.com/wireguard/wgctrl"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
)
2023-10-05 18:48:54 +02:00
// CrdtNodeManager manages nodes in the crdt mesh
type CrdtNodeManager struct {
2023-10-06 19:25:38 +02:00
MeshId string
2023-10-05 18:48:54 +02:00
IfName string
2023-10-06 12:52:51 +02:00
Client *wgctrl.Client
2023-10-05 18:48:54 +02:00
doc *automerge.Doc
}
func (c *CrdtNodeManager) AddNode(crdt MeshNodeCrdt) {
c.doc.Path("nodes").Map().Set(crdt.PublicKey, crdt)
}
2023-10-06 12:52:51 +02:00
func (c *CrdtNodeManager) applyWg() error {
snapshot, err := c.GetCrdt()
if err != nil {
return err
}
updateWgConf(c.IfName, snapshot.Nodes, *c.Client)
return nil
}
2023-10-05 18:48:54 +02:00
// GetCrdt(): Converts the document into a struct
func (c *CrdtNodeManager) GetCrdt() (*MeshCrdt, error) {
return automerge.As[*MeshCrdt](c.doc.Root())
}
// Load: Load an entire mesh network
func (c *CrdtNodeManager) Load(bytes []byte) error {
doc, err := automerge.Load(bytes)
if err != nil {
return err
}
c.doc = doc
2023-10-06 12:52:51 +02:00
c.applyWg()
2023-10-05 18:48:54 +02:00
return nil
}
// Save: Save an entire mesh network
2023-10-06 12:52:51 +02:00
func (c *CrdtNodeManager) Save() []byte {
2023-10-05 18:48:54 +02:00
return c.doc.Save()
}
2023-10-06 12:52:51 +02:00
func (c *CrdtNodeManager) LoadChanges(changes []byte) error {
err := c.doc.LoadIncremental(changes)
if err != nil {
return err
}
return c.applyWg()
2023-10-05 18:48:54 +02:00
}
func (c *CrdtNodeManager) SaveChanges() []byte {
2023-10-06 12:52:51 +02:00
return c.doc.SaveIncremental()
2023-10-05 18:48:54 +02:00
}
// NewCrdtNodeManager: Create a new crdt node manager
2023-10-06 12:52:51 +02:00
func NewCrdtNodeManager(meshId, devName string, client *wgctrl.Client) *CrdtNodeManager {
2023-10-05 18:48:54 +02:00
var manager CrdtNodeManager
2023-10-06 19:25:38 +02:00
manager.MeshId = meshId
2023-10-05 18:48:54 +02:00
manager.doc = automerge.New()
manager.IfName = devName
2023-10-06 12:52:51 +02:00
manager.Client = client
2023-10-05 18:48:54 +02:00
return &manager
}
2023-10-06 12:52:51 +02:00
func convertMeshNode(node MeshNodeCrdt) (*wgtypes.PeerConfig, error) {
peerEndpoint, err := net.ResolveUDPAddr("udp", node.WgEndpoint)
if err != nil {
return nil, err
}
peerPublic, err := wgtypes.ParseKey(node.PublicKey)
if err != nil {
return nil, err
}
allowedIps := make([]net.IPNet, 1)
_, ipnet, err := net.ParseCIDR(node.WgHost)
if err != nil {
return nil, err
}
allowedIps[0] = *ipnet
peerConfig := wgtypes.PeerConfig{
PublicKey: peerPublic,
Endpoint: peerEndpoint,
AllowedIPs: allowedIps,
}
return &peerConfig, nil
}
func (m1 *MeshNodeCrdt) Compare(m2 *MeshNodeCrdt) int {
return strings.Compare(m1.PublicKey, m2.PublicKey)
}
2023-10-06 12:52:51 +02:00
func updateWgConf(devName string, nodes map[string]MeshNodeCrdt, client wgctrl.Client) error {
peerConfigs := make([]wgtypes.PeerConfig, len(nodes))
var count int = 0
for _, n := range nodes {
peer, err := convertMeshNode(n)
logging.InfoLog.Println(n.HostEndpoint)
if err != nil {
return err
}
peerConfigs[count] = *peer
count++
}
cfg := wgtypes.Config{
Peers: peerConfigs,
ReplacePeers: true,
}
client.ConfigureDevice(devName, cfg)
return nil
}