smegmesh/pkg/sync/syncrequester.go

170 lines
3.8 KiB
Go
Raw Normal View History

2023-10-10 21:14:40 +02:00
package sync
import (
"context"
"errors"
2023-10-23 19:13:08 +02:00
"io"
2023-10-10 21:14:40 +02:00
"time"
"github.com/tim-beatham/smegmesh/pkg/conf"
"github.com/tim-beatham/smegmesh/pkg/conn"
logging "github.com/tim-beatham/smegmesh/pkg/log"
"github.com/tim-beatham/smegmesh/pkg/mesh"
"github.com/tim-beatham/smegmesh/pkg/rpc"
2023-10-10 21:14:40 +02:00
)
// SyncRequester: coordinates the syncing of meshes
type SyncRequester interface {
GetMesh(meshId string, ifName string, port int, endPoint string) error
SyncMesh(meshid string, meshNode mesh.MeshNode) error
2023-10-10 21:14:40 +02:00
}
type SyncRequesterImpl struct {
manager mesh.MeshManager
connectionManager conn.ConnectionManager
configuration *conf.DaemonConfiguration
errorHdlr SyncErrorHandler
2023-10-10 21:14:40 +02:00
}
// GetMesh: Retrieves the local state of the mesh at the endpoint
func (s *SyncRequesterImpl) GetMesh(meshId string, ifName string, port int, endPoint string) error {
peerConnection, err := s.connectionManager.GetConnection(endPoint)
2023-10-10 21:14:40 +02:00
if err != nil {
return err
}
client, err := peerConnection.GetClient()
if err != nil {
return err
}
c := rpc.NewSyncServiceClient(client)
2023-10-24 01:12:38 +02:00
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
2023-10-10 21:14:40 +02:00
defer cancel()
reply, err := c.GetConf(ctx, &rpc.GetConfRequest{MeshId: meshId})
if err != nil {
return err
}
err = s.manager.AddMesh(&mesh.AddMeshParams{
MeshId: meshId,
WgPort: port,
MeshBytes: reply.Mesh,
})
2023-10-10 21:14:40 +02:00
return err
}
// handleErr: handleGrpc errors
func (s *SyncRequesterImpl) handleErr(meshId, pubKey string, err error) error {
ok := s.errorHdlr.Handle(meshId, pubKey, err)
if ok {
return nil
}
return err
}
2023-10-10 21:14:40 +02:00
// SyncMesh: Proactively send a sync request to the other mesh
func (s *SyncRequesterImpl) SyncMesh(meshId string, meshNode mesh.MeshNode) error {
endpoint := meshNode.GetHostEndpoint()
pubKey, _ := meshNode.GetPublicKey()
peerConnection, err := s.connectionManager.GetConnection(endpoint)
2023-10-10 21:14:40 +02:00
if err != nil {
return err
}
client, err := peerConnection.GetClient()
if err != nil {
return err
}
mesh := s.manager.GetMesh(meshId)
2023-10-10 21:14:40 +02:00
if mesh == nil {
return errors.New("mesh does not exist")
}
c := rpc.NewSyncServiceClient(client)
syncTimeOut := float64(s.configuration.SyncTime) * float64(time.Second)
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(syncTimeOut))
2023-10-10 21:14:40 +02:00
defer cancel()
err = s.syncMesh(mesh, ctx, c)
2023-10-10 21:14:40 +02:00
if err != nil {
s.handleErr(meshId, pubKey.String(), err)
2023-10-10 21:14:40 +02:00
}
logging.Log.WriteInfof("synced with node: %s meshId: %s\n", endpoint, meshId)
return err
2023-10-10 21:14:40 +02:00
}
func (s *SyncRequesterImpl) syncMesh(mesh mesh.MeshProvider, ctx context.Context, client rpc.SyncServiceClient) error {
2023-10-23 19:13:08 +02:00
stream, err := client.SyncMesh(ctx)
syncer := mesh.GetSyncer()
if err != nil {
return err
}
for {
msg, moreMessages := syncer.GenerateMessage()
err := stream.Send(&rpc.SyncMeshRequest{MeshId: mesh.GetMeshId(), Changes: msg})
2023-10-23 19:13:08 +02:00
if err != nil {
return err
}
in, err := stream.Recv()
if err != nil && err != io.EOF {
logging.Log.WriteInfof("stream recv error: %s\n", err.Error())
2023-10-23 19:13:08 +02:00
return err
}
if err != io.EOF && len(in.Changes) != 0 {
err = syncer.RecvMessage(in.Changes)
}
if err != nil {
logging.Log.WriteInfof("syncer recv error: %s\n", err.Error())
2023-10-23 19:13:08 +02:00
return err
}
if !moreMessages {
break
}
}
syncer.Complete()
2023-10-23 19:13:08 +02:00
stream.CloseSend()
return nil
}
type NewSyncRequesterParams struct {
MeshManager mesh.MeshManager
ConnectionManager conn.ConnectionManager
Configuration *conf.DaemonConfiguration
}
func NewSyncRequester(params NewSyncRequesterParams) SyncRequester {
errorHdlr := NewSyncErrorHandler(params.MeshManager, params.ConnectionManager)
return &SyncRequesterImpl{manager: params.MeshManager,
connectionManager: params.ConnectionManager,
configuration: params.Configuration,
errorHdlr: errorHdlr,
}
}