WIP document deletion
This commit is contained in:
parent
8805ba78ef
commit
d09a802487
@ -31,18 +31,20 @@ func (a aclKeys) RawRecordKey(id string) []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type treeKeys struct {
|
type treeKeys struct {
|
||||||
id string
|
id string
|
||||||
spaceId string
|
spaceId string
|
||||||
headsKey []byte
|
headsKey []byte
|
||||||
rootKey []byte
|
rootKey []byte
|
||||||
|
rawChangePrefix []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTreeKeys(spaceId, id string) treeKeys {
|
func newTreeKeys(spaceId, id string) treeKeys {
|
||||||
return treeKeys{
|
return treeKeys{
|
||||||
id: id,
|
id: id,
|
||||||
spaceId: spaceId,
|
spaceId: spaceId,
|
||||||
headsKey: storage.JoinStringsToBytes("space", spaceId, "t", id, "heads"),
|
headsKey: storage.JoinStringsToBytes("space", spaceId, "t", id, "heads"),
|
||||||
rootKey: storage.JoinStringsToBytes("space", spaceId, "t", "rootId", id),
|
rootKey: storage.JoinStringsToBytes("space", spaceId, "t", "rootId", id),
|
||||||
|
rawChangePrefix: storage.JoinStringsToBytes("space", spaceId, "t", id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,6 +60,10 @@ func (t treeKeys) RawChangeKey(id string) []byte {
|
|||||||
return storage.JoinStringsToBytes("space", t.spaceId, "t", t.id, id)
|
return storage.JoinStringsToBytes("space", t.spaceId, "t", t.id, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t treeKeys) RawChangePrefix() []byte {
|
||||||
|
return t.rawChangePrefix
|
||||||
|
}
|
||||||
|
|
||||||
type spaceKeys struct {
|
type spaceKeys struct {
|
||||||
headerKey []byte
|
headerKey []byte
|
||||||
treePrefixKey []byte
|
treePrefixKey []byte
|
||||||
|
|||||||
@ -133,3 +133,45 @@ func (t *treeStorage) GetRawChange(ctx context.Context, id string) (raw *treecha
|
|||||||
func (t *treeStorage) HasChange(ctx context.Context, id string) (bool, error) {
|
func (t *treeStorage) HasChange(ctx context.Context, id string) (bool, error) {
|
||||||
return hasDB(t.db, t.keys.RawChangeKey(id)), nil
|
return hasDB(t.db, t.keys.RawChangeKey(id)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *treeStorage) Delete() (err error) {
|
||||||
|
storedKeys, err := t.storedKeys()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = t.db.Update(func(txn *badger.Txn) error {
|
||||||
|
for _, k := range storedKeys {
|
||||||
|
err = txn.Delete(k)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *treeStorage) storedKeys() (keys [][]byte, err error) {
|
||||||
|
err = t.db.View(func(txn *badger.Txn) error {
|
||||||
|
opts := badger.DefaultIteratorOptions
|
||||||
|
opts.PrefetchValues = false
|
||||||
|
opts.Prefix = t.keys.RawChangePrefix()
|
||||||
|
|
||||||
|
it := txn.NewIterator(opts)
|
||||||
|
defer it.Close()
|
||||||
|
|
||||||
|
for it.Rewind(); it.Valid(); it.Next() {
|
||||||
|
item := it.Item()
|
||||||
|
key := item.Key()
|
||||||
|
// if it is a heads key
|
||||||
|
if len(key) <= len(t.keys.HeadsKey()) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
keyCopy := make([]byte, 0, len(key))
|
||||||
|
keyCopy = item.KeyCopy(key)
|
||||||
|
keys = append(keys, keyCopy)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
@ -1,28 +0,0 @@
|
|||||||
package deletionservice
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/account"
|
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Service interface {
|
|
||||||
}
|
|
||||||
|
|
||||||
const deletionChangeType = "space.deletionlist"
|
|
||||||
|
|
||||||
type service struct {
|
|
||||||
account account.Service
|
|
||||||
}
|
|
||||||
|
|
||||||
func New() Service {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func deriveDeletionTreePayload(account account.Service, spaceId string) tree.ObjectTreeCreatePayload {
|
|
||||||
return tree.ObjectTreeCreatePayload{
|
|
||||||
SignKey: account.Account().SignKey,
|
|
||||||
ChangeType: deletionChangeType,
|
|
||||||
SpaceId: spaceId,
|
|
||||||
Identity: account.Account().Identity,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -3,7 +3,9 @@ package commonspace
|
|||||||
import (
|
import (
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
|
||||||
aclrecordproto2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto"
|
aclrecordproto "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto"
|
||||||
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/common"
|
||||||
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/cid"
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/cid"
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/signingkey"
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/signingkey"
|
||||||
"hash/fnv"
|
"hash/fnv"
|
||||||
@ -11,6 +13,11 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SpaceSettingsChangeType = "reserved.spacesettings"
|
||||||
|
SpaceDerivationScheme = "derivation.standard"
|
||||||
|
)
|
||||||
|
|
||||||
func storagePayloadForSpaceCreate(payload SpaceCreatePayload) (storagePayload storage.SpaceStorageCreatePayload, err error) {
|
func storagePayloadForSpaceCreate(payload SpaceCreatePayload) (storagePayload storage.SpaceStorageCreatePayload, err error) {
|
||||||
// unmarshalling signing and encryption keys
|
// unmarshalling signing and encryption keys
|
||||||
identity, err := payload.SigningKey.GetPublic().Raw()
|
identity, err := payload.SigningKey.GetPublic().Raw()
|
||||||
@ -23,8 +30,8 @@ func storagePayloadForSpaceCreate(payload SpaceCreatePayload) (storagePayload st
|
|||||||
}
|
}
|
||||||
|
|
||||||
// preparing header and space id
|
// preparing header and space id
|
||||||
bytes := make([]byte, 32)
|
spaceHeaderSeed := make([]byte, 32)
|
||||||
_, err = rand.Read(bytes)
|
_, err = rand.Read(spaceHeaderSeed)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -33,7 +40,7 @@ func storagePayloadForSpaceCreate(payload SpaceCreatePayload) (storagePayload st
|
|||||||
Timestamp: time.Now().UnixNano(),
|
Timestamp: time.Now().UnixNano(),
|
||||||
SpaceType: payload.SpaceType,
|
SpaceType: payload.SpaceType,
|
||||||
ReplicationKey: payload.ReplicationKey,
|
ReplicationKey: payload.ReplicationKey,
|
||||||
Seed: bytes,
|
Seed: spaceHeaderSeed,
|
||||||
}
|
}
|
||||||
marshalled, err := header.Marshal()
|
marshalled, err := header.Marshal()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -68,12 +75,11 @@ func storagePayloadForSpaceCreate(payload SpaceCreatePayload) (storagePayload st
|
|||||||
}
|
}
|
||||||
|
|
||||||
// preparing acl
|
// preparing acl
|
||||||
aclRoot := &aclrecordproto2.ACLRoot{
|
aclRoot := &aclrecordproto.ACLRoot{
|
||||||
Identity: identity,
|
Identity: identity,
|
||||||
EncryptionKey: encPubKey,
|
EncryptionKey: encPubKey,
|
||||||
SpaceId: spaceId,
|
SpaceId: spaceId,
|
||||||
EncryptedReadKey: encReadKey,
|
EncryptedReadKey: encReadKey,
|
||||||
DerivationScheme: "",
|
|
||||||
CurrentReadKeyHash: readKeyHash,
|
CurrentReadKeyHash: readKeyHash,
|
||||||
Timestamp: time.Now().UnixNano(),
|
Timestamp: time.Now().UnixNano(),
|
||||||
}
|
}
|
||||||
@ -82,10 +88,31 @@ func storagePayloadForSpaceCreate(payload SpaceCreatePayload) (storagePayload st
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
builder := tree.NewChangeBuilder(common.NewKeychain(), nil)
|
||||||
|
spaceSettingsSeed := make([]byte, 32)
|
||||||
|
_, err = rand.Read(spaceSettingsSeed)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, settingsRoot, err := builder.BuildInitialContent(tree.InitialContent{
|
||||||
|
AclHeadId: rawWithId.Id,
|
||||||
|
Identity: aclRoot.Identity,
|
||||||
|
SigningKey: payload.SigningKey,
|
||||||
|
SpaceId: spaceId,
|
||||||
|
Seed: spaceSettingsSeed,
|
||||||
|
ChangeType: SpaceSettingsChangeType,
|
||||||
|
Timestamp: time.Now().UnixNano(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// creating storage
|
// creating storage
|
||||||
storagePayload = storage.SpaceStorageCreatePayload{
|
storagePayload = storage.SpaceStorageCreatePayload{
|
||||||
AclWithId: rawWithId,
|
AclWithId: rawWithId,
|
||||||
SpaceHeaderWithId: rawHeaderWithId,
|
SpaceHeaderWithId: rawHeaderWithId,
|
||||||
|
SpaceSettingsWithId: settingsRoot,
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -144,7 +171,7 @@ func storagePayloadForSpaceDerive(payload SpaceDerivePayload) (storagePayload st
|
|||||||
}
|
}
|
||||||
|
|
||||||
// deriving and encrypting read key
|
// deriving and encrypting read key
|
||||||
readKey, err := aclrecordproto2.ACLReadKeyDerive(signPrivKey, encPrivKey)
|
readKey, err := aclrecordproto.ACLReadKeyDerive(signPrivKey, encPrivKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -160,29 +187,41 @@ func storagePayloadForSpaceDerive(payload SpaceDerivePayload) (storagePayload st
|
|||||||
}
|
}
|
||||||
|
|
||||||
// preparing acl
|
// preparing acl
|
||||||
aclRoot := &aclrecordproto2.ACLRoot{
|
aclRoot := &aclrecordproto.ACLRoot{
|
||||||
Identity: identity,
|
Identity: identity,
|
||||||
EncryptionKey: encPubKey,
|
EncryptionKey: encPubKey,
|
||||||
SpaceId: spaceId,
|
SpaceId: spaceId,
|
||||||
EncryptedReadKey: encReadKey,
|
EncryptedReadKey: encReadKey,
|
||||||
DerivationScheme: "",
|
DerivationScheme: SpaceDerivationScheme,
|
||||||
CurrentReadKeyHash: readKeyHash,
|
CurrentReadKeyHash: readKeyHash,
|
||||||
Timestamp: time.Now().UnixNano(),
|
|
||||||
}
|
}
|
||||||
rawWithId, err := marshalACLRoot(aclRoot, payload.SigningKey)
|
rawWithId, err := marshalACLRoot(aclRoot, payload.SigningKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
builder := tree.NewChangeBuilder(common.NewKeychain(), nil)
|
||||||
|
_, settingsRoot, err := builder.BuildInitialContent(tree.InitialContent{
|
||||||
|
AclHeadId: rawWithId.Id,
|
||||||
|
Identity: aclRoot.Identity,
|
||||||
|
SigningKey: payload.SigningKey,
|
||||||
|
SpaceId: spaceId,
|
||||||
|
ChangeType: SpaceSettingsChangeType,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// creating storage
|
// creating storage
|
||||||
storagePayload = storage.SpaceStorageCreatePayload{
|
storagePayload = storage.SpaceStorageCreatePayload{
|
||||||
AclWithId: rawWithId,
|
AclWithId: rawWithId,
|
||||||
SpaceHeaderWithId: rawHeaderWithId,
|
SpaceHeaderWithId: rawHeaderWithId,
|
||||||
|
SpaceSettingsWithId: settingsRoot,
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func marshalACLRoot(aclRoot *aclrecordproto2.ACLRoot, key signingkey.PrivKey) (rawWithId *aclrecordproto2.RawACLRecordWithId, err error) {
|
func marshalACLRoot(aclRoot *aclrecordproto.ACLRoot, key signingkey.PrivKey) (rawWithId *aclrecordproto.RawACLRecordWithId, err error) {
|
||||||
marshalledRoot, err := aclRoot.Marshal()
|
marshalledRoot, err := aclRoot.Marshal()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -191,7 +230,7 @@ func marshalACLRoot(aclRoot *aclrecordproto2.ACLRoot, key signingkey.PrivKey) (r
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
raw := &aclrecordproto2.RawACLRecord{
|
raw := &aclrecordproto.RawACLRecord{
|
||||||
Payload: marshalledRoot,
|
Payload: marshalledRoot,
|
||||||
Signature: signature,
|
Signature: signature,
|
||||||
}
|
}
|
||||||
@ -203,7 +242,7 @@ func marshalACLRoot(aclRoot *aclrecordproto2.ACLRoot, key signingkey.PrivKey) (r
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rawWithId = &aclrecordproto2.RawACLRecordWithId{
|
rawWithId = &aclrecordproto.RawACLRecordWithId{
|
||||||
Payload: marshalledRaw,
|
Payload: marshalledRaw,
|
||||||
Id: aclHeadId,
|
Id: aclHeadId,
|
||||||
}
|
}
|
||||||
|
|||||||
22
common/commonspace/settingsservice/service.go
Normal file
22
common/commonspace/settingsservice/service.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package settingsservice
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/account"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service interface {
|
||||||
|
}
|
||||||
|
|
||||||
|
const deletionChangeType = "space.deletionlist"
|
||||||
|
|
||||||
|
type service struct {
|
||||||
|
account account.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() Service {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type DeletedDocumentNotifiable interface {
|
||||||
|
NotifyDeleted(id string)
|
||||||
|
}
|
||||||
@ -141,6 +141,7 @@ func (s *space) Init(ctx context.Context) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s.aclList = syncacl.NewSyncACL(aclList, s.syncService.StreamPool())
|
s.aclList = syncacl.NewSyncACL(aclList, s.syncService.StreamPool())
|
||||||
objectGetter := newCommonSpaceGetter(s.id, s.aclList, s.cache)
|
objectGetter := newCommonSpaceGetter(s.id, s.aclList, s.cache)
|
||||||
s.syncService.Init(objectGetter)
|
s.syncService.Init(objectGetter)
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger"
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger"
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice"
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice"
|
||||||
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsservice"
|
||||||
spacestorage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
|
spacestorage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice"
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice"
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice/synchandler"
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice/synchandler"
|
||||||
@ -18,15 +19,20 @@ import (
|
|||||||
"github.com/gogo/protobuf/proto"
|
"github.com/gogo/protobuf/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrSyncTreeClosed = errors.New("sync tree is closed")
|
var (
|
||||||
|
ErrSyncTreeClosed = errors.New("sync tree is closed")
|
||||||
|
ErrSyncTreeDeleted = errors.New("sync tree is deleted")
|
||||||
|
)
|
||||||
|
|
||||||
// SyncTree sends head updates to sync service and also sends new changes to update listener
|
// SyncTree sends head updates to sync service and also sends new changes to update listener
|
||||||
type SyncTree struct {
|
type SyncTree struct {
|
||||||
tree.ObjectTree
|
tree.ObjectTree
|
||||||
synchandler.SyncHandler
|
synchandler.SyncHandler
|
||||||
syncClient SyncClient
|
syncClient SyncClient
|
||||||
listener updatelistener.UpdateListener
|
listener updatelistener.UpdateListener
|
||||||
isClosed bool
|
deletedNotifiable settingsservice.DeletedDocumentNotifiable
|
||||||
|
isClosed bool
|
||||||
|
isDeleted bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var log = logger.NewNamed("commonspace.synctree").Sugar()
|
var log = logger.NewNamed("commonspace.synctree").Sugar()
|
||||||
@ -37,25 +43,27 @@ var buildObjectTree = tree.BuildObjectTree
|
|||||||
var createSyncClient = newSyncClient
|
var createSyncClient = newSyncClient
|
||||||
|
|
||||||
type CreateDeps struct {
|
type CreateDeps struct {
|
||||||
SpaceId string
|
SpaceId string
|
||||||
Payload tree.ObjectTreeCreatePayload
|
Payload tree.ObjectTreeCreatePayload
|
||||||
Configuration nodeconf.Configuration
|
Configuration nodeconf.Configuration
|
||||||
HeadNotifiable diffservice.HeadNotifiable
|
HeadNotifiable diffservice.HeadNotifiable
|
||||||
StreamPool syncservice.StreamPool
|
StreamPool syncservice.StreamPool
|
||||||
Listener updatelistener.UpdateListener
|
Listener updatelistener.UpdateListener
|
||||||
AclList list.ACLList
|
AclList list.ACLList
|
||||||
CreateStorage storage.TreeStorageCreatorFunc
|
CreateStorage storage.TreeStorageCreatorFunc
|
||||||
|
DeletedNotifiable settingsservice.DeletedDocumentNotifiable
|
||||||
}
|
}
|
||||||
|
|
||||||
type BuildDeps struct {
|
type BuildDeps struct {
|
||||||
SpaceId string
|
SpaceId string
|
||||||
StreamPool syncservice.StreamPool
|
StreamPool syncservice.StreamPool
|
||||||
Configuration nodeconf.Configuration
|
Configuration nodeconf.Configuration
|
||||||
HeadNotifiable diffservice.HeadNotifiable
|
HeadNotifiable diffservice.HeadNotifiable
|
||||||
Listener updatelistener.UpdateListener
|
Listener updatelistener.UpdateListener
|
||||||
AclList list.ACLList
|
AclList list.ACLList
|
||||||
SpaceStorage spacestorage.SpaceStorage
|
SpaceStorage spacestorage.SpaceStorage
|
||||||
TreeStorage storage.TreeStorage
|
TreeStorage storage.TreeStorage
|
||||||
|
DeletedNotifiable settingsservice.DeletedDocumentNotifiable
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeriveSyncTree(ctx context.Context, deps CreateDeps) (t tree.ObjectTree, err error) {
|
func DeriveSyncTree(ctx context.Context, deps CreateDeps) (t tree.ObjectTree, err error) {
|
||||||
@ -70,9 +78,10 @@ func DeriveSyncTree(ctx context.Context, deps CreateDeps) (t tree.ObjectTree, er
|
|||||||
sharedFactory,
|
sharedFactory,
|
||||||
deps.Configuration)
|
deps.Configuration)
|
||||||
syncTree := &SyncTree{
|
syncTree := &SyncTree{
|
||||||
ObjectTree: t,
|
ObjectTree: t,
|
||||||
syncClient: syncClient,
|
syncClient: syncClient,
|
||||||
listener: deps.Listener,
|
listener: deps.Listener,
|
||||||
|
deletedNotifiable: deps.DeletedNotifiable,
|
||||||
}
|
}
|
||||||
syncHandler := newSyncTreeHandler(syncTree, syncClient)
|
syncHandler := newSyncTreeHandler(syncTree, syncClient)
|
||||||
syncTree.SyncHandler = syncHandler
|
syncTree.SyncHandler = syncHandler
|
||||||
@ -95,9 +104,10 @@ func CreateSyncTree(ctx context.Context, deps CreateDeps) (t tree.ObjectTree, er
|
|||||||
GetRequestFactory(),
|
GetRequestFactory(),
|
||||||
deps.Configuration)
|
deps.Configuration)
|
||||||
syncTree := &SyncTree{
|
syncTree := &SyncTree{
|
||||||
ObjectTree: t,
|
ObjectTree: t,
|
||||||
syncClient: syncClient,
|
syncClient: syncClient,
|
||||||
listener: deps.Listener,
|
listener: deps.Listener,
|
||||||
|
deletedNotifiable: deps.DeletedNotifiable,
|
||||||
}
|
}
|
||||||
syncHandler := newSyncTreeHandler(syncTree, syncClient)
|
syncHandler := newSyncTreeHandler(syncTree, syncClient)
|
||||||
syncTree.SyncHandler = syncHandler
|
syncTree.SyncHandler = syncHandler
|
||||||
@ -175,9 +185,10 @@ func buildSyncTree(ctx context.Context, isFirstBuild bool, deps BuildDeps) (t tr
|
|||||||
GetRequestFactory(),
|
GetRequestFactory(),
|
||||||
deps.Configuration)
|
deps.Configuration)
|
||||||
syncTree := &SyncTree{
|
syncTree := &SyncTree{
|
||||||
ObjectTree: t,
|
ObjectTree: t,
|
||||||
syncClient: syncClient,
|
syncClient: syncClient,
|
||||||
listener: deps.Listener,
|
listener: deps.Listener,
|
||||||
|
deletedNotifiable: deps.DeletedNotifiable,
|
||||||
}
|
}
|
||||||
syncHandler := newSyncTreeHandler(syncTree, syncClient)
|
syncHandler := newSyncTreeHandler(syncTree, syncClient)
|
||||||
syncTree.SyncHandler = syncHandler
|
syncTree.SyncHandler = syncHandler
|
||||||
@ -196,8 +207,7 @@ func buildSyncTree(ctx context.Context, isFirstBuild bool, deps BuildDeps) (t tr
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *SyncTree) AddContent(ctx context.Context, content tree.SignableChangeContent) (res tree.AddResult, err error) {
|
func (s *SyncTree) AddContent(ctx context.Context, content tree.SignableChangeContent) (res tree.AddResult, err error) {
|
||||||
if s.isClosed { // checkAlive err
|
if err = s.checkAlive(); err != nil {
|
||||||
err = ErrSyncTreeClosed
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
res, err = s.ObjectTree.AddContent(ctx, content)
|
res, err = s.ObjectTree.AddContent(ctx, content)
|
||||||
@ -210,8 +220,7 @@ func (s *SyncTree) AddContent(ctx context.Context, content tree.SignableChangeCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *SyncTree) AddRawChanges(ctx context.Context, changes ...*treechangeproto.RawTreeChangeWithId) (res tree.AddResult, err error) {
|
func (s *SyncTree) AddRawChanges(ctx context.Context, changes ...*treechangeproto.RawTreeChangeWithId) (res tree.AddResult, err error) {
|
||||||
if s.isClosed {
|
if err = s.checkAlive(); err != nil {
|
||||||
err = ErrSyncTreeClosed
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
res, err = s.ObjectTree.AddRawChanges(ctx, changes...)
|
res, err = s.ObjectTree.AddRawChanges(ctx, changes...)
|
||||||
@ -235,15 +244,44 @@ func (s *SyncTree) AddRawChanges(ctx context.Context, changes ...*treechangeprot
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SyncTree) Delete() (err error) {
|
||||||
|
log.With("id", s.ID()).Debug("deleting sync tree")
|
||||||
|
s.Lock()
|
||||||
|
defer func() {
|
||||||
|
s.Unlock()
|
||||||
|
if err == nil {
|
||||||
|
s.deletedNotifiable.NotifyDeleted(s.ID())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if err = s.checkAlive(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = s.ObjectTree.Delete()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.isDeleted = true
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (s *SyncTree) Close() (err error) {
|
func (s *SyncTree) Close() (err error) {
|
||||||
log.With("id", s.ID()).Debug("closing sync tree")
|
log.With("id", s.ID()).Debug("closing sync tree")
|
||||||
s.Lock()
|
s.Lock()
|
||||||
defer s.Unlock()
|
defer s.Unlock()
|
||||||
log.With("id", s.ID()).Debug("taken lock on sync tree")
|
if err = s.checkAlive(); err != nil {
|
||||||
if s.isClosed {
|
|
||||||
err = ErrSyncTreeClosed
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.isClosed = true
|
s.isClosed = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SyncTree) checkAlive() (err error) {
|
||||||
|
if s.isClosed {
|
||||||
|
err = ErrSyncTreeClosed
|
||||||
|
}
|
||||||
|
if s.isDeleted {
|
||||||
|
err = ErrSyncTreeDeleted
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
@ -142,6 +142,10 @@ func (t *inMemoryTreeStorage) GetRawChange(ctx context.Context, changeId string)
|
|||||||
return nil, fmt.Errorf("could not get change with id: %s", changeId)
|
return nil, fmt.Errorf("could not get change with id: %s", changeId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *inMemoryTreeStorage) Delete() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type inMemoryStorageProvider struct {
|
type inMemoryStorageProvider struct {
|
||||||
objects map[string]TreeStorage
|
objects map[string]TreeStorage
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
|
|||||||
@ -14,6 +14,7 @@ type TreeStorage interface {
|
|||||||
AddRawChange(change *treechangeproto.RawTreeChangeWithId) error
|
AddRawChange(change *treechangeproto.RawTreeChangeWithId) error
|
||||||
GetRawChange(ctx context.Context, id string) (*treechangeproto.RawTreeChangeWithId, error)
|
GetRawChange(ctx context.Context, id string) (*treechangeproto.RawTreeChangeWithId, error)
|
||||||
HasChange(ctx context.Context, id string) (bool, error)
|
HasChange(ctx context.Context, id string) (bool, error)
|
||||||
|
Delete() error
|
||||||
}
|
}
|
||||||
|
|
||||||
type TreeStorageCreatorFunc = func(payload TreeStorageCreatePayload) (TreeStorage, error)
|
type TreeStorageCreatorFunc = func(payload TreeStorageCreatePayload) (TreeStorage, error)
|
||||||
|
|||||||
@ -48,7 +48,7 @@ type changeBuilder struct {
|
|||||||
keys *common.Keychain
|
keys *common.Keychain
|
||||||
}
|
}
|
||||||
|
|
||||||
func newChangeBuilder(keys *common.Keychain, rootChange *treechangeproto.RawTreeChangeWithId) ChangeBuilder {
|
func NewChangeBuilder(keys *common.Keychain, rootChange *treechangeproto.RawTreeChangeWithId) ChangeBuilder {
|
||||||
return &changeBuilder{keys: keys, rootChange: rootChange}
|
return &changeBuilder{keys: keys, rootChange: rootChange}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -57,6 +57,7 @@ type ObjectTree interface {
|
|||||||
AddContent(ctx context.Context, content SignableChangeContent) (AddResult, error)
|
AddContent(ctx context.Context, content SignableChangeContent) (AddResult, error)
|
||||||
AddRawChanges(ctx context.Context, changes ...*treechangeproto.RawTreeChangeWithId) (AddResult, error)
|
AddRawChanges(ctx context.Context, changes ...*treechangeproto.RawTreeChangeWithId) (AddResult, error)
|
||||||
|
|
||||||
|
Delete() error
|
||||||
Close() error
|
Close() error
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +101,7 @@ func defaultObjectTreeDeps(
|
|||||||
aclList list2.ACLList) objectTreeDeps {
|
aclList list2.ACLList) objectTreeDeps {
|
||||||
|
|
||||||
keychain := common.NewKeychain()
|
keychain := common.NewKeychain()
|
||||||
changeBuilder := newChangeBuilder(keychain, rootChange)
|
changeBuilder := NewChangeBuilder(keychain, rootChange)
|
||||||
treeBuilder := newTreeBuilder(treeStorage, changeBuilder)
|
treeBuilder := newTreeBuilder(treeStorage, changeBuilder)
|
||||||
return objectTreeDeps{
|
return objectTreeDeps{
|
||||||
changeBuilder: changeBuilder,
|
changeBuilder: changeBuilder,
|
||||||
@ -508,6 +509,10 @@ func (ot *objectTree) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ot *objectTree) Delete() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ot *objectTree) SnapshotPath() []string {
|
func (ot *objectTree) SnapshotPath() []string {
|
||||||
// TODO: Add error as return parameter
|
// TODO: Add error as return parameter
|
||||||
if ot.snapshotPathIsActual() {
|
if ot.snapshotPathIsActual() {
|
||||||
|
|||||||
@ -116,7 +116,7 @@ func prepareTreeContext(t *testing.T, aclList list.ACLList) testTreeContext {
|
|||||||
treeStorage := changeCreator.createNewTreeStorage("0", aclList.Head().Id)
|
treeStorage := changeCreator.createNewTreeStorage("0", aclList.Head().Id)
|
||||||
root, _ := treeStorage.Root()
|
root, _ := treeStorage.Root()
|
||||||
changeBuilder := &mockChangeBuilder{
|
changeBuilder := &mockChangeBuilder{
|
||||||
originalBuilder: newChangeBuilder(nil, root),
|
originalBuilder: NewChangeBuilder(nil, root),
|
||||||
}
|
}
|
||||||
deps := objectTreeDeps{
|
deps := objectTreeDeps{
|
||||||
changeBuilder: changeBuilder,
|
changeBuilder: changeBuilder,
|
||||||
|
|||||||
@ -71,7 +71,7 @@ func createObjectTree(
|
|||||||
Seed: seed,
|
Seed: seed,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, raw, err := newChangeBuilder(common.NewKeychain(), nil).BuildInitialContent(cnt)
|
_, raw, err := NewChangeBuilder(common.NewKeychain(), nil).BuildInitialContent(cnt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package storage
|
package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@ -25,6 +26,7 @@ func (a aclKeys) RawRecordKey(id string) []byte {
|
|||||||
|
|
||||||
type treeKeys struct {
|
type treeKeys struct {
|
||||||
id string
|
id string
|
||||||
|
prefix string
|
||||||
headsKey []byte
|
headsKey []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,6 +34,7 @@ func newTreeKeys(id string) treeKeys {
|
|||||||
return treeKeys{
|
return treeKeys{
|
||||||
id: id,
|
id: id,
|
||||||
headsKey: storage.JoinStringsToBytes("t", id, "heads"),
|
headsKey: storage.JoinStringsToBytes("t", id, "heads"),
|
||||||
|
prefix: fmt.Sprintf("t/%s", id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,6 +46,10 @@ func (t treeKeys) RawChangeKey(id string) []byte {
|
|||||||
return storage.JoinStringsToBytes("t", t.id, id)
|
return storage.JoinStringsToBytes("t", t.id, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t treeKeys) isTreeRecordKey(key string) bool {
|
||||||
|
return strings.HasPrefix(key, t.prefix) && !strings.HasSuffix(key, "/heads")
|
||||||
|
}
|
||||||
|
|
||||||
type spaceKeys struct {
|
type spaceKeys struct {
|
||||||
headerKey []byte
|
headerKey []byte
|
||||||
}
|
}
|
||||||
|
|||||||
@ -135,3 +135,36 @@ func (t *treeStorage) GetRawChange(ctx context.Context, id string) (raw *treecha
|
|||||||
func (t *treeStorage) HasChange(ctx context.Context, id string) (bool, error) {
|
func (t *treeStorage) HasChange(ctx context.Context, id string) (bool, error) {
|
||||||
return t.db.Has(t.keys.RawChangeKey(id))
|
return t.db.Has(t.keys.RawChangeKey(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *treeStorage) Delete() (err error) {
|
||||||
|
storedKeys, err := t.storedKeys()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, k := range storedKeys {
|
||||||
|
err = t.db.Delete(k)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *treeStorage) storedKeys() (keys [][]byte, err error) {
|
||||||
|
index := t.db.Items()
|
||||||
|
|
||||||
|
key, _, err := index.Next()
|
||||||
|
for err == nil {
|
||||||
|
strKey := string(key)
|
||||||
|
if t.keys.isTreeRecordKey(strKey) {
|
||||||
|
keys = append(keys, key)
|
||||||
|
}
|
||||||
|
key, _, err = index.Next()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != pogreb.ErrIterationDone {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = nil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user