1
0
Fork 0
mirror of https://github.com/anyproto/any-sync.git synced 2025-06-12 02:30:41 +09:00
any-sync/commonspace/headsync/headsync.go
2024-01-25 13:27:47 +01:00

185 lines
5.7 KiB
Go

//go:generate mockgen -destination mock_headsync/mock_headsync.go github.com/anyproto/any-sync/commonspace/headsync DiffSyncer
package headsync
import (
"context"
"time"
"go.uber.org/zap"
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/app/ldiff"
"github.com/anyproto/any-sync/app/logger"
"github.com/anyproto/any-sync/commonspace/config"
"github.com/anyproto/any-sync/commonspace/credentialprovider"
"github.com/anyproto/any-sync/commonspace/deletionstate"
"github.com/anyproto/any-sync/commonspace/object/acl/syncacl"
"github.com/anyproto/any-sync/commonspace/object/treesyncer"
"github.com/anyproto/any-sync/commonspace/peermanager"
"github.com/anyproto/any-sync/commonspace/spacestate"
"github.com/anyproto/any-sync/commonspace/spacestorage"
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
"github.com/anyproto/any-sync/commonspace/syncstatus"
"github.com/anyproto/any-sync/nodeconf"
"github.com/anyproto/any-sync/util/periodicsync"
"github.com/anyproto/any-sync/util/slice"
)
var log = logger.NewNamed(CName)
const CName = "common.commonspace.headsync"
type TreeHeads struct {
Id string
Heads []string
}
type HeadSync interface {
app.ComponentRunnable
ExternalIds() []string
DebugAllHeads() (res []TreeHeads)
AllIds() []string
UpdateHeads(id string, heads []string)
HandleRangeRequest(ctx context.Context, req *spacesyncproto.HeadSyncRequest) (resp *spacesyncproto.HeadSyncResponse, err error)
RemoveObjects(ids []string)
}
type headSync struct {
spaceId string
syncPeriod int
periodicSync periodicsync.PeriodicSync
storage spacestorage.SpaceStorage
diffContainer ldiff.DiffContainer
log logger.CtxLogger
syncer DiffSyncer
configuration nodeconf.NodeConf
peerManager peermanager.PeerManager
treeSyncer treesyncer.TreeSyncer
credentialProvider credentialprovider.CredentialProvider
syncStatus syncstatus.StatusService
deletionState deletionstate.ObjectDeletionState
syncAcl syncacl.SyncAcl
}
func New() HeadSync {
return &headSync{}
}
var createDiffSyncer = newDiffSyncer
func (h *headSync) Init(a *app.App) (err error) {
shared := a.MustComponent(spacestate.CName).(*spacestate.SpaceState)
cfg := a.MustComponent("config").(config.ConfigGetter)
h.syncAcl = a.MustComponent(syncacl.CName).(syncacl.SyncAcl)
h.spaceId = shared.SpaceId
h.syncPeriod = cfg.GetSpace().SyncPeriod
h.configuration = a.MustComponent(nodeconf.CName).(nodeconf.NodeConf)
h.log = log.With(zap.String("spaceId", h.spaceId))
h.storage = a.MustComponent(spacestorage.CName).(spacestorage.SpaceStorage)
h.diffContainer = ldiff.NewDiffContainer(32, 256)
h.peerManager = a.MustComponent(peermanager.CName).(peermanager.PeerManager)
h.credentialProvider = a.MustComponent(credentialprovider.CName).(credentialprovider.CredentialProvider)
h.syncStatus = a.MustComponent(syncstatus.CName).(syncstatus.StatusService)
h.treeSyncer = a.MustComponent(treesyncer.CName).(treesyncer.TreeSyncer)
h.deletionState = a.MustComponent(deletionstate.CName).(deletionstate.ObjectDeletionState)
h.syncer = createDiffSyncer(h)
sync := func(ctx context.Context) (err error) {
return h.syncer.Sync(ctx)
}
h.periodicSync = periodicsync.NewPeriodicSync(h.syncPeriod, time.Minute, sync, h.log)
h.syncAcl.SetHeadUpdater(h)
// TODO: move to run?
h.syncer.Init()
return nil
}
func (h *headSync) Name() (name string) {
return CName
}
func (h *headSync) Run(ctx context.Context) (err error) {
initialIds, err := h.storage.StoredIds()
if err != nil {
return
}
h.fillDiff(initialIds)
h.periodicSync.Run()
return
}
func (h *headSync) HandleRangeRequest(ctx context.Context, req *spacesyncproto.HeadSyncRequest) (resp *spacesyncproto.HeadSyncResponse, err error) {
if req.DiffType == spacesyncproto.DiffType_Precalculated {
return HandleRangeRequest(ctx, h.diffContainer.PrecalculatedDiff(), req)
} else {
return HandleRangeRequest(ctx, h.diffContainer.InitialDiff(), req)
}
}
func (h *headSync) UpdateHeads(id string, heads []string) {
h.syncer.UpdateHeads(id, heads)
}
func (h *headSync) AllIds() []string {
return h.diffContainer.PrecalculatedDiff().Ids()
}
func (h *headSync) ExternalIds() []string {
settingsId := h.storage.SpaceSettingsId()
aclId := h.syncAcl.Id()
return slice.DiscardFromSlice(h.AllIds(), func(id string) bool {
return id == settingsId || id == aclId
})
}
func (h *headSync) DebugAllHeads() (res []TreeHeads) {
els := h.diffContainer.PrecalculatedDiff().Elements()
for _, el := range els {
idHead := TreeHeads{
Id: el.Id,
Heads: splitString(el.Head),
}
res = append(res, idHead)
}
return
}
func (h *headSync) RemoveObjects(ids []string) {
h.syncer.RemoveObjects(ids)
}
func (h *headSync) Close(ctx context.Context) (err error) {
h.storage.WriteOldSpaceHash(h.diffContainer.InitialDiff().Hash())
h.periodicSync.Close()
return
}
func (h *headSync) fillDiff(objectIds []string) {
var els = make([]ldiff.Element, 0, len(objectIds))
for _, id := range objectIds {
st, err := h.storage.TreeStorage(id)
if err != nil {
continue
}
heads, err := st.Heads()
if err != nil {
continue
}
els = append(els, ldiff.Element{
Id: id,
Head: concatStrings(heads),
})
}
els = append(els, ldiff.Element{
Id: h.syncAcl.Id(),
Head: h.syncAcl.Head().Id,
})
log.Debug("setting acl", zap.String("aclId", h.syncAcl.Id()), zap.String("headId", h.syncAcl.Head().Id))
h.diffContainer.Set(els...)
if err := h.storage.WriteSpaceHash(h.diffContainer.PrecalculatedDiff().Hash()); err != nil {
h.log.Error("can't write space hash", zap.Error(err))
}
if err := h.storage.WriteOldSpaceHash(h.diffContainer.InitialDiff().Hash()); err != nil {
h.log.Error("can't write old space hash", zap.Error(err))
}
}