2022-11-13 14:16:58 +01:00

158 lines
4.0 KiB
Go

package settingsdocument
import (
"context"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/account"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
spacestorage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
)
type SettingsDocument interface {
tree.ObjectTree
Init(ctx context.Context) (err error)
Refresh()
DeleteObject(id string) (err error)
NotifyObjectUpdate(id string)
}
type BuildTreeFunc func(ctx context.Context, id string, listener updatelistener.UpdateListener) (t tree.ObjectTree, err error)
type RemoveObjectsFunc func([]string)
type Deps struct {
BuildFunc BuildTreeFunc
Account account.Service
TreeGetter treegetter.TreeGetter
Store spacestorage.SpaceStorage
RemoveFunc RemoveObjectsFunc
// prov exists mainly for the ease of testing
prov deletedIdsProvider
}
type settingsDocument struct {
tree.ObjectTree
account account.Service
spaceId string
treeGetter treegetter.TreeGetter
store spacestorage.SpaceStorage
prov deletedIdsProvider
removeNotifyFunc RemoveObjectsFunc
buildFunc BuildTreeFunc
queue *settingsQueue
documentIds []string
lastChangeId string
}
func NewSettingsDocument(deps Deps, spaceId string) (doc SettingsDocument, err error) {
s := &settingsDocument{
account: deps.Account,
spaceId: spaceId,
queue: newSettingsQueue(),
treeGetter: deps.TreeGetter,
store: deps.Store,
removeNotifyFunc: deps.RemoveFunc,
buildFunc: deps.BuildFunc,
}
// this is needed mainly for testing
if deps.prov == nil {
s.prov = &provider{}
}
doc = s
return
}
func (s *settingsDocument) NotifyObjectUpdate(id string) {
s.queue.queueIfDeleted(id)
}
func (s *settingsDocument) Update(tr tree.ObjectTree) {
ids, lastId, err := s.prov.ProvideIds(tr, s.lastChangeId)
if err != nil {
return
}
s.documentIds = append(s.documentIds, ids...)
s.lastChangeId = lastId
s.queue.add(ids)
s.removeNotifyFunc(ids)
s.deleteQueued()
}
func (s *settingsDocument) Rebuild(tr tree.ObjectTree) {
ids, lastId, err := s.prov.ProvideIds(tr, "")
if err != nil {
return
}
s.documentIds = ids
s.lastChangeId = lastId
s.queue.add(ids)
s.removeNotifyFunc(ids)
s.deleteQueued()
}
func (s *settingsDocument) Init(ctx context.Context) (err error) {
s.ObjectTree, err = s.buildFunc(ctx, s.store.SpaceSettingsId(), s)
return
}
func (s *settingsDocument) Refresh() {
s.Lock()
defer s.Unlock()
if s.lastChangeId == "" {
s.Rebuild(s)
} else {
s.deleteQueued()
}
}
func (s *settingsDocument) deleteQueued() {
allQueued := s.queue.getQueued()
for _, id := range allQueued {
if _, err := s.store.TreeStorage(id); err == nil {
err := s.treeGetter.DeleteTree(context.Background(), s.spaceId, id)
if err != nil {
// TODO: some errors may tell us that the tree is actually deleted, so we should have more checks here
// TODO: add logging
continue
}
}
s.queue.delete(id)
}
}
func (s *settingsDocument) DeleteObject(id string) (err error) {
s.Lock()
defer s.Unlock()
if s.queue.exists(id) {
return nil
}
content := &spacesyncproto.SpaceSettingsContent_ObjectDelete{
ObjectDelete: &spacesyncproto.ObjectDelete{Id: id},
}
change := &spacesyncproto.SettingsData{
Content: []*spacesyncproto.SpaceSettingsContent{
{content},
},
Snapshot: nil,
}
res, err := change.Marshal()
if err != nil {
return
}
_, err = s.AddContent(context.Background(), tree.SignableChangeContent{
Data: res,
Key: s.account.Account().SignKey,
Identity: s.account.Account().Identity,
IsSnapshot: false,
IsEncrypted: false,
})
if err == nil {
s.Update(s)
}
return
}