From d9452509b54d803b13861854e723d5d6e1f0a22b Mon Sep 17 00:00:00 2001 From: mcrakhman Date: Sat, 16 Jul 2022 14:24:27 +0200 Subject: [PATCH] WIP new document logic --- pkg/acl/acltree/acltree.go | 49 ++++++++++++++----- service/sync/requesthandler/requesthandler.go | 31 ++++++++---- service/treecache/service.go | 5 ++ 3 files changed, 65 insertions(+), 20 deletions(-) diff --git a/pkg/acl/acltree/acltree.go b/pkg/acl/acltree/acltree.go index 5cd85957..ed1c1a45 100644 --- a/pkg/acl/acltree/acltree.go +++ b/pkg/acl/acltree/acltree.go @@ -46,6 +46,7 @@ var ErrNoCommonSnapshot = errors.New("trees doesn't have a common snapshot") type ACLTree interface { RWLocker + ID() string ACLState() *ACLState AddContent(ctx context.Context, f func(builder ChangeBuilder) error) (*Change, error) AddRawChanges(ctx context.Context, changes ...*aclpb.RawChange) (AddResult, error) @@ -65,6 +66,7 @@ type aclTree struct { accountData *account.AccountData updateListener TreeUpdateListener + id string fullTree *Tree aclTreeFromStart *Tree // TODO: right now we don't use it, we can probably have only local var for now. This tree is built from start of the document aclState *ACLState @@ -112,6 +114,10 @@ func BuildACLTree( if err != nil { return nil, err } + aclTree.id, err = t.TreeID() + if err != nil { + return nil, err + } listener.Rebuild(aclTree) @@ -214,6 +220,10 @@ func (a *aclTree) rebuildFromStorage(fromStart bool) error { return nil } +func (a *aclTree) ID() string { + return a.id +} + func (a *aclTree) ACLState() *ACLState { return a.aclState } @@ -400,13 +410,25 @@ func (a *aclTree) SnapshotPath() []string { func (a *aclTree) ChangesAfterCommonSnapshot(theirPath []string) ([]*aclpb.RawChange, error) { // TODO: think about when the clients will have their full acl tree and thus full snapshots // but no changes after some of the snapshots - commonSnapshot, err := a.commonSnapshotForTwoPaths(a.SnapshotPath(), theirPath) - if err != nil { - return nil, err + + var ( + isNewDocument = len(theirPath) != 0 + ourPath = a.SnapshotPath() + // by default returning everything we have + commonSnapshot = ourPath[len(ourPath)-1] // TODO: root snapshot, probably it is better to have a specific method in treestorage + err error + ) + + // if this is non-empty request + if !isNewDocument { + commonSnapshot, err = a.commonSnapshotForTwoPaths(ourPath, theirPath) + if err != nil { + return nil, err + } } - // we presume that we have everything after the common snapshot, though this may not be the case in case of clients and only ACL tree changes - changes, err := a.treeBuilder.dfs(a.fullTree.Heads(), commonSnapshot, func(id string) (*Change, error) { - // using custom load function to skip verification step and save raw changes + var rawChanges []*aclpb.RawChange + // using custom load function to skip verification step and save raw changes + load := func(id string) (*Change, error) { raw, err := a.treeStorage.GetChange(context.Background(), id) if err != nil { return nil, err @@ -418,16 +440,21 @@ func (a *aclTree) ChangesAfterCommonSnapshot(theirPath []string) ([]*aclpb.RawCh } ch := NewChange(id, aclChange) - ch.Raw = raw + rawChanges = append(rawChanges, raw) return ch, nil - }) + } + // we presume that we have everything after the common snapshot, though this may not be the case in case of clients and only ACL tree changes + _, err = a.treeBuilder.dfs(a.fullTree.Heads(), commonSnapshot, load) if err != nil { return nil, err } - var rawChanges []*aclpb.RawChange - for _, ch := range changes { - rawChanges = append(rawChanges, ch.Raw) + if isNewDocument { + _, err = load(commonSnapshot) + if err != nil { + return nil, err + } } + return rawChanges, nil } diff --git a/service/sync/requesthandler/requesthandler.go b/service/sync/requesthandler/requesthandler.go index 702cf909..491f3c4b 100644 --- a/service/sync/requesthandler/requesthandler.go +++ b/service/sync/requesthandler/requesthandler.go @@ -6,6 +6,7 @@ import ( "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclchanges/aclpb" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/acltree" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treestorage" + "github.com/anytypeio/go-anytype-infrastructure-experiments/service/account" "github.com/anytypeio/go-anytype-infrastructure-experiments/service/sync/client" "github.com/anytypeio/go-anytype-infrastructure-experiments/service/sync/syncpb" "github.com/anytypeio/go-anytype-infrastructure-experiments/service/treecache" @@ -15,6 +16,7 @@ import ( type requestHandler struct { treeCache treecache.Service client client.Client + account account.Service } func NewRequestHandler() app.Component { @@ -31,6 +33,8 @@ const CName = "SyncRequestHandler" func (r *requestHandler) Init(ctx context.Context, a *app.App) (err error) { r.treeCache = a.MustComponent(treecache.CName).(treecache.Service) + r.client = a.MustComponent(client.CName).(client.Client) + r.account = a.MustComponent(account.CName).(account.Service) return nil } @@ -102,9 +106,12 @@ func (r *requestHandler) HandleFullSyncRequest(ctx context.Context, senderId str err = r.treeCache.Do(ctx, request.TreeId, func(tree acltree.ACLTree) error { // TODO: check if we already have those changes - result, err = tree.AddRawChanges(ctx, request.Changes...) - if err != nil { - return err + // if we have non empty request + if len(request.Heads) != 0 { + result, err = tree.AddRawChanges(ctx, request.Changes...) + if err != nil { + return err + } } snapshotPath = tree.SnapshotPath() fullResponse, err = r.prepareFullSyncResponse(request.TreeId, request.SnapshotPath, request.Changes, tree) @@ -132,23 +139,24 @@ func (r *requestHandler) HandleFullSyncRequest(ctx context.Context, senderId str return r.client.NotifyHeadsChanged(newUpdate) } -func (r *requestHandler) HandleFullSyncResponse(ctx context.Context, senderId string, request *syncpb.SyncFullRequest) (err error) { +func (r *requestHandler) HandleFullSyncResponse(ctx context.Context, senderId string, response *syncpb.SyncFullResponse) (err error) { var ( snapshotPath []string result acltree.AddResult ) - err = r.treeCache.Do(ctx, request.TreeId, func(tree acltree.ACLTree) error { + err = r.treeCache.Do(ctx, response.TreeId, func(tree acltree.ACLTree) error { // TODO: check if we already have those changes - result, err = tree.AddRawChanges(ctx, request.Changes...) + result, err = tree.AddRawChanges(ctx, response.Changes...) if err != nil { return err } snapshotPath = tree.SnapshotPath() return nil }) - if err != nil { - return err + if err == treestorage.ErrUnknownTreeId { + // TODO: probably sometimes we should notify about this (e.g. if client created new document) + return r.createTree(response) } // if error or nothing has changed if err != nil || len(result.Added) == 0 { @@ -161,7 +169,7 @@ func (r *requestHandler) HandleFullSyncResponse(ctx context.Context, senderId st Heads: result.Heads, Changes: result.Added, SnapshotPath: snapshotPath, - TreeId: request.TreeId, + TreeId: response.TreeId, } return r.client.NotifyHeadsChanged(newUpdate) } @@ -205,3 +213,8 @@ func (r *requestHandler) prepareFullSyncResponse(treeId string, theirPath []stri SnapshotPath: tree.SnapshotPath(), }, nil } + +func (r *requestHandler) createTree(response *syncpb.SyncFullResponse) error { + // TODO: write create tree functionality + return nil +} diff --git a/service/treecache/service.go b/service/treecache/service.go index 654d12ca..cd3cf884 100644 --- a/service/treecache/service.go +++ b/service/treecache/service.go @@ -13,6 +13,7 @@ const CName = "treecache" type Service interface { Do(ctx context.Context, treeId string, f func(tree acltree.ACLTree) error) error + Add(ctx context.Context, treeId string, tree acltree.ACLTree) error } type service struct { @@ -37,6 +38,10 @@ func (s *service) Do(ctx context.Context, treeId string, f func(tree acltree.ACL return f(tree.(acltree.ACLTree)) } +func (s *service) Add(ctx context.Context, treeId string, tree acltree.ACLTree) error { + return s.cache.Add(treeId, tree) +} + func (s *service) Init(ctx context.Context, a *app.App) (err error) { s.cache = ocache.New(s.loadTree) s.account = a.MustComponent(account.CName).(account.Service)