mirror of
https://github.com/anyproto/any-sync.git
synced 2025-06-08 05:57:03 +09:00
Moving parts, refactoring for deletion
This commit is contained in:
parent
e02abc153c
commit
17a6f7cb55
26 changed files with 412 additions and 526 deletions
|
@ -1,4 +1,4 @@
|
||||||
package settings
|
package deletionmanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
|
@ -1,7 +1,8 @@
|
||||||
package settings
|
package deletionmanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/anyproto/any-sync/app/logger"
|
||||||
"github.com/anyproto/any-sync/commonspace/deletionstate"
|
"github.com/anyproto/any-sync/commonspace/deletionstate"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
|
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/treemanager"
|
"github.com/anyproto/any-sync/commonspace/object/treemanager"
|
||||||
|
@ -17,10 +18,11 @@ type deleter struct {
|
||||||
st spacestorage.SpaceStorage
|
st spacestorage.SpaceStorage
|
||||||
state deletionstate.ObjectDeletionState
|
state deletionstate.ObjectDeletionState
|
||||||
getter treemanager.TreeManager
|
getter treemanager.TreeManager
|
||||||
|
log logger.CtxLogger
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDeleter(st spacestorage.SpaceStorage, state deletionstate.ObjectDeletionState, getter treemanager.TreeManager) Deleter {
|
func newDeleter(st spacestorage.SpaceStorage, state deletionstate.ObjectDeletionState, getter treemanager.TreeManager, log logger.CtxLogger) Deleter {
|
||||||
return &deleter{st, state, getter}
|
return &deleter{st, state, getter, log}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *deleter) Delete() {
|
func (d *deleter) Delete() {
|
||||||
|
@ -29,7 +31,7 @@ func (d *deleter) Delete() {
|
||||||
spaceId = d.st.Id()
|
spaceId = d.st.Id()
|
||||||
)
|
)
|
||||||
for _, id := range allQueued {
|
for _, id := range allQueued {
|
||||||
log := log.With(zap.String("treeId", id), zap.String("spaceId", spaceId))
|
log := d.log.With(zap.String("treeId", id))
|
||||||
shouldDelete, err := d.tryMarkDeleted(spaceId, id)
|
shouldDelete, err := d.tryMarkDeleted(spaceId, id)
|
||||||
if !shouldDelete {
|
if !shouldDelete {
|
||||||
if err != nil {
|
if err != nil {
|
|
@ -1,4 +1,4 @@
|
||||||
package settings
|
package deletionmanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -16,7 +16,7 @@ func TestDeleter_Delete(t *testing.T) {
|
||||||
st := mock_spacestorage.NewMockSpaceStorage(ctrl)
|
st := mock_spacestorage.NewMockSpaceStorage(ctrl)
|
||||||
delState := mock_deletionstate.NewMockObjectDeletionState(ctrl)
|
delState := mock_deletionstate.NewMockObjectDeletionState(ctrl)
|
||||||
|
|
||||||
deleter := newDeleter(st, delState, treeManager)
|
deleter := newDeleter(st, delState, treeManager, log)
|
||||||
|
|
||||||
t.Run("deleter delete mark deleted success", func(t *testing.T) {
|
t.Run("deleter delete mark deleted success", func(t *testing.T) {
|
||||||
id := "id"
|
id := "id"
|
||||||
|
@ -50,7 +50,7 @@ func TestDeleter_Delete(t *testing.T) {
|
||||||
|
|
||||||
deleter.Delete()
|
deleter.Delete()
|
||||||
})
|
})
|
||||||
//treeManager.EXPECT().DeleteTree(gomock.Any(), spaceId, id).Return(spacestorage.ErrTreeStorageAlreadyDeleted)
|
|
||||||
t.Run("deleter delete success", func(t *testing.T) {
|
t.Run("deleter delete success", func(t *testing.T) {
|
||||||
id := "id"
|
id := "id"
|
||||||
spaceId := "spaceId"
|
spaceId := "spaceId"
|
74
commonspace/deletionmanager/deletionmanager.go
Normal file
74
commonspace/deletionmanager/deletionmanager.go
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
//go:generate mockgen -destination mock_deletionmanager/mock_deletionmanager.go github.com/anyproto/any-sync/commonspace/deletionmanager DeletionManager,Deleter,SpaceIdsProvider
|
||||||
|
package deletionmanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/anyproto/any-sync/app"
|
||||||
|
"github.com/anyproto/any-sync/app/logger"
|
||||||
|
"github.com/anyproto/any-sync/commonspace/deletionstate"
|
||||||
|
"github.com/anyproto/any-sync/commonspace/object/treemanager"
|
||||||
|
"github.com/anyproto/any-sync/commonspace/settings/settingsstate"
|
||||||
|
"github.com/anyproto/any-sync/commonspace/spacestate"
|
||||||
|
"github.com/anyproto/any-sync/commonspace/spacestorage"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SpaceIdsProvider interface {
|
||||||
|
app.Component
|
||||||
|
AllIds() []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type DeletionManager interface {
|
||||||
|
app.ComponentRunnable
|
||||||
|
UpdateState(ctx context.Context, state *settingsstate.State) (err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() DeletionManager {
|
||||||
|
return &deletionManager{}
|
||||||
|
}
|
||||||
|
|
||||||
|
const CName = "common.commonspace.deletionmanager"
|
||||||
|
|
||||||
|
var log = logger.NewNamed(CName)
|
||||||
|
|
||||||
|
type deletionManager struct {
|
||||||
|
deletionState deletionstate.ObjectDeletionState
|
||||||
|
deleter Deleter
|
||||||
|
loop *deleteLoop
|
||||||
|
log logger.CtxLogger
|
||||||
|
|
||||||
|
spaceId string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *deletionManager) Init(a *app.App) (err error) {
|
||||||
|
state := a.MustComponent(spacestate.CName).(*spacestate.SpaceState)
|
||||||
|
storage := a.MustComponent(spacestorage.CName).(spacestorage.SpaceStorage)
|
||||||
|
d.log = log.With(zap.String("spaceId", state.SpaceId), zap.String("settingsId", storage.SpaceSettingsId()))
|
||||||
|
d.deletionState = a.MustComponent(deletionstate.CName).(deletionstate.ObjectDeletionState)
|
||||||
|
treeManager := a.MustComponent(treemanager.CName).(treemanager.TreeManager)
|
||||||
|
d.deleter = newDeleter(storage, d.deletionState, treeManager, d.log)
|
||||||
|
d.loop = newDeleteLoop(d.deleter.Delete)
|
||||||
|
d.deletionState.AddObserver(func(ids []string) {
|
||||||
|
d.loop.notify()
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *deletionManager) Name() (name string) {
|
||||||
|
return CName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *deletionManager) Run(ctx context.Context) (err error) {
|
||||||
|
d.loop.Run()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *deletionManager) Close(ctx context.Context) (err error) {
|
||||||
|
d.loop.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *deletionManager) UpdateState(ctx context.Context, state *settingsstate.State) error {
|
||||||
|
d.deletionState.Add(state.DeletedIds)
|
||||||
|
return nil
|
||||||
|
}
|
86
commonspace/deletionmanager/deletionmanager_test.go
Normal file
86
commonspace/deletionmanager/deletionmanager_test.go
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
package deletionmanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/anyproto/any-sync/app"
|
||||||
|
"github.com/anyproto/any-sync/commonspace/deletionmanager/mock_deletionmanager"
|
||||||
|
"github.com/anyproto/any-sync/commonspace/deletionstate"
|
||||||
|
"github.com/anyproto/any-sync/commonspace/deletionstate/mock_deletionstate"
|
||||||
|
"github.com/anyproto/any-sync/commonspace/object/treemanager"
|
||||||
|
"github.com/anyproto/any-sync/commonspace/object/treemanager/mock_treemanager"
|
||||||
|
"github.com/anyproto/any-sync/commonspace/settings/settingsstate"
|
||||||
|
"github.com/anyproto/any-sync/commonspace/spacestate"
|
||||||
|
"github.com/anyproto/any-sync/commonspace/spacestorage"
|
||||||
|
"github.com/anyproto/any-sync/commonspace/spacestorage/mock_spacestorage"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"go.uber.org/mock/gomock"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type deletionManagerFixture struct {
|
||||||
|
delState *mock_deletionstate.MockObjectDeletionState
|
||||||
|
treeManager *mock_treemanager.MockTreeManager
|
||||||
|
storage *mock_spacestorage.MockSpaceStorage
|
||||||
|
deleter *mock_deletionmanager.MockDeleter
|
||||||
|
spaceState *spacestate.SpaceState
|
||||||
|
settingsId string
|
||||||
|
|
||||||
|
app *app.App
|
||||||
|
delManager *deletionManager
|
||||||
|
|
||||||
|
ctrl *gomock.Controller
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDelManagerFixture(t *testing.T) *deletionManagerFixture {
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
spaceState := &spacestate.SpaceState{
|
||||||
|
SpaceId: "spaceId",
|
||||||
|
}
|
||||||
|
fx := &deletionManagerFixture{
|
||||||
|
delState: mock_deletionstate.NewMockObjectDeletionState(ctrl),
|
||||||
|
treeManager: mock_treemanager.NewMockTreeManager(ctrl),
|
||||||
|
storage: mock_spacestorage.NewMockSpaceStorage(ctrl),
|
||||||
|
deleter: mock_deletionmanager.NewMockDeleter(ctrl),
|
||||||
|
spaceState: spaceState,
|
||||||
|
settingsId: "settingsId",
|
||||||
|
delManager: New().(*deletionManager),
|
||||||
|
ctrl: ctrl,
|
||||||
|
app: &app.App{},
|
||||||
|
}
|
||||||
|
return fx
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fx *deletionManagerFixture) init(t *testing.T) {
|
||||||
|
fx.delState.EXPECT().Name().AnyTimes().Return(deletionstate.CName)
|
||||||
|
fx.treeManager.EXPECT().Name().AnyTimes().Return(treemanager.CName)
|
||||||
|
fx.storage.EXPECT().Name().AnyTimes().Return(spacestorage.CName)
|
||||||
|
fx.storage.EXPECT().SpaceSettingsId().AnyTimes().Return(fx.settingsId)
|
||||||
|
fx.delState.EXPECT().AddObserver(gomock.Any())
|
||||||
|
fx.app.Register(fx.spaceState).
|
||||||
|
Register(fx.storage).
|
||||||
|
Register(fx.delState).
|
||||||
|
Register(fx.treeManager).
|
||||||
|
Register(fx.delManager)
|
||||||
|
|
||||||
|
err := fx.delManager.Init(fx.app)
|
||||||
|
require.NoError(t, err)
|
||||||
|
fx.delManager.deleter = fx.deleter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fx *deletionManagerFixture) stop() {
|
||||||
|
fx.ctrl.Finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeletionManager_UpdateState(t *testing.T) {
|
||||||
|
fx := newDelManagerFixture(t)
|
||||||
|
fx.init(t)
|
||||||
|
defer fx.stop()
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
state := &settingsstate.State{
|
||||||
|
DeletedIds: map[string]struct{}{"id": {}},
|
||||||
|
}
|
||||||
|
fx.delState.EXPECT().Add(state.DeletedIds)
|
||||||
|
err := fx.delManager.UpdateState(ctx, state)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
|
@ -1,13 +1,14 @@
|
||||||
// Code generated by MockGen. DO NOT EDIT.
|
// Code generated by MockGen. DO NOT EDIT.
|
||||||
// Source: github.com/anyproto/any-sync/commonspace/settings (interfaces: DeletionManager,Deleter,SpaceIdsProvider)
|
// Source: github.com/anyproto/any-sync/commonspace/deletionmanager (interfaces: DeletionManager,Deleter,SpaceIdsProvider)
|
||||||
|
|
||||||
// Package mock_settings is a generated GoMock package.
|
// Package mock_deletionmanager is a generated GoMock package.
|
||||||
package mock_settings
|
package mock_deletionmanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
context "context"
|
context "context"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
|
|
||||||
|
app "github.com/anyproto/any-sync/app"
|
||||||
settingsstate "github.com/anyproto/any-sync/commonspace/settings/settingsstate"
|
settingsstate "github.com/anyproto/any-sync/commonspace/settings/settingsstate"
|
||||||
gomock "go.uber.org/mock/gomock"
|
gomock "go.uber.org/mock/gomock"
|
||||||
)
|
)
|
||||||
|
@ -35,6 +36,62 @@ func (m *MockDeletionManager) EXPECT() *MockDeletionManagerMockRecorder {
|
||||||
return m.recorder
|
return m.recorder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close mocks base method.
|
||||||
|
func (m *MockDeletionManager) Close(arg0 context.Context) error {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "Close", arg0)
|
||||||
|
ret0, _ := ret[0].(error)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close indicates an expected call of Close.
|
||||||
|
func (mr *MockDeletionManagerMockRecorder) Close(arg0 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockDeletionManager)(nil).Close), arg0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init mocks base method.
|
||||||
|
func (m *MockDeletionManager) Init(arg0 *app.App) error {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "Init", arg0)
|
||||||
|
ret0, _ := ret[0].(error)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init indicates an expected call of Init.
|
||||||
|
func (mr *MockDeletionManagerMockRecorder) Init(arg0 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Init", reflect.TypeOf((*MockDeletionManager)(nil).Init), arg0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name mocks base method.
|
||||||
|
func (m *MockDeletionManager) Name() string {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "Name")
|
||||||
|
ret0, _ := ret[0].(string)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name indicates an expected call of Name.
|
||||||
|
func (mr *MockDeletionManagerMockRecorder) Name() *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockDeletionManager)(nil).Name))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run mocks base method.
|
||||||
|
func (m *MockDeletionManager) Run(arg0 context.Context) error {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "Run", arg0)
|
||||||
|
ret0, _ := ret[0].(error)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run indicates an expected call of Run.
|
||||||
|
func (mr *MockDeletionManagerMockRecorder) Run(arg0 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Run", reflect.TypeOf((*MockDeletionManager)(nil).Run), arg0)
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateState mocks base method.
|
// UpdateState mocks base method.
|
||||||
func (m *MockDeletionManager) UpdateState(arg0 context.Context, arg1 *settingsstate.State) error {
|
func (m *MockDeletionManager) UpdateState(arg0 context.Context, arg1 *settingsstate.State) error {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
@ -120,3 +177,31 @@ func (mr *MockSpaceIdsProviderMockRecorder) AllIds() *gomock.Call {
|
||||||
mr.mock.ctrl.T.Helper()
|
mr.mock.ctrl.T.Helper()
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AllIds", reflect.TypeOf((*MockSpaceIdsProvider)(nil).AllIds))
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AllIds", reflect.TypeOf((*MockSpaceIdsProvider)(nil).AllIds))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Init mocks base method.
|
||||||
|
func (m *MockSpaceIdsProvider) Init(arg0 *app.App) error {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "Init", arg0)
|
||||||
|
ret0, _ := ret[0].(error)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init indicates an expected call of Init.
|
||||||
|
func (mr *MockSpaceIdsProviderMockRecorder) Init(arg0 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Init", reflect.TypeOf((*MockSpaceIdsProvider)(nil).Init), arg0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name mocks base method.
|
||||||
|
func (m *MockSpaceIdsProvider) Name() string {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "Name")
|
||||||
|
ret0, _ := ret[0].(string)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name indicates an expected call of Name.
|
||||||
|
func (mr *MockSpaceIdsProviderMockRecorder) Name() *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockSpaceIdsProvider)(nil).Name))
|
||||||
|
}
|
|
@ -407,12 +407,13 @@ func (a *aclRecordBuilder) Unmarshall(rawRecord *consensusproto.RawRecord) (rec
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rec = &AclRecord{
|
rec = &AclRecord{
|
||||||
PrevId: aclRecord.PrevId,
|
PrevId: aclRecord.PrevId,
|
||||||
Timestamp: aclRecord.Timestamp,
|
Timestamp: aclRecord.Timestamp,
|
||||||
Data: aclRecord.Data,
|
AcceptorTimestamp: rawRecord.AcceptorTimestamp,
|
||||||
Signature: rawRecord.Signature,
|
Data: aclRecord.Data,
|
||||||
Identity: pubKey,
|
Signature: rawRecord.Signature,
|
||||||
Model: aclData,
|
Identity: pubKey,
|
||||||
|
Model: aclData,
|
||||||
}
|
}
|
||||||
res, err := pubKey.Verify(rawRecord.Payload, rawRecord.Signature)
|
res, err := pubKey.Verify(rawRecord.Payload, rawRecord.Signature)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -264,45 +264,45 @@ func (st *AclState) saveKeysFromRoot(id string, root *aclrecordproto.AclRoot) (e
|
||||||
func (st *AclState) applyChangeData(record *AclRecord) (err error) {
|
func (st *AclState) applyChangeData(record *AclRecord) (err error) {
|
||||||
model := record.Model.(*aclrecordproto.AclData)
|
model := record.Model.(*aclrecordproto.AclData)
|
||||||
for _, ch := range model.GetAclContent() {
|
for _, ch := range model.GetAclContent() {
|
||||||
if err = st.applyChangeContent(ch, record.Id, record.Identity); err != nil {
|
if err = st.applyChangeContent(ch, record); err != nil {
|
||||||
log.Info("error while applying changes: %v; ignore", zap.Error(err))
|
log.Info("error while applying changes; ignore", zap.Error(err))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *AclState) applyChangeContent(ch *aclrecordproto.AclContentValue, recordId string, authorIdentity crypto.PubKey) error {
|
func (st *AclState) applyChangeContent(ch *aclrecordproto.AclContentValue, record *AclRecord) error {
|
||||||
switch {
|
switch {
|
||||||
case ch.GetPermissionChange() != nil:
|
case ch.GetPermissionChange() != nil:
|
||||||
return st.applyPermissionChange(ch.GetPermissionChange(), recordId, authorIdentity)
|
return st.applyPermissionChange(ch.GetPermissionChange(), record)
|
||||||
case ch.GetInvite() != nil:
|
case ch.GetInvite() != nil:
|
||||||
return st.applyInvite(ch.GetInvite(), recordId, authorIdentity)
|
return st.applyInvite(ch.GetInvite(), record)
|
||||||
case ch.GetInviteRevoke() != nil:
|
case ch.GetInviteRevoke() != nil:
|
||||||
return st.applyInviteRevoke(ch.GetInviteRevoke(), recordId, authorIdentity)
|
return st.applyInviteRevoke(ch.GetInviteRevoke(), record)
|
||||||
case ch.GetRequestJoin() != nil:
|
case ch.GetRequestJoin() != nil:
|
||||||
return st.applyRequestJoin(ch.GetRequestJoin(), recordId, authorIdentity)
|
return st.applyRequestJoin(ch.GetRequestJoin(), record)
|
||||||
case ch.GetRequestAccept() != nil:
|
case ch.GetRequestAccept() != nil:
|
||||||
return st.applyRequestAccept(ch.GetRequestAccept(), recordId, authorIdentity)
|
return st.applyRequestAccept(ch.GetRequestAccept(), record)
|
||||||
case ch.GetRequestDecline() != nil:
|
case ch.GetRequestDecline() != nil:
|
||||||
return st.applyRequestDecline(ch.GetRequestDecline(), recordId, authorIdentity)
|
return st.applyRequestDecline(ch.GetRequestDecline(), record)
|
||||||
case ch.GetAccountRemove() != nil:
|
case ch.GetAccountRemove() != nil:
|
||||||
return st.applyAccountRemove(ch.GetAccountRemove(), recordId, authorIdentity)
|
return st.applyAccountRemove(ch.GetAccountRemove(), record)
|
||||||
case ch.GetReadKeyChange() != nil:
|
case ch.GetReadKeyChange() != nil:
|
||||||
return st.applyReadKeyChange(ch.GetReadKeyChange(), recordId, authorIdentity, true)
|
return st.applyReadKeyChange(ch.GetReadKeyChange(), record, true)
|
||||||
case ch.GetAccountRequestRemove() != nil:
|
case ch.GetAccountRequestRemove() != nil:
|
||||||
return st.applyRequestRemove(ch.GetAccountRequestRemove(), recordId, authorIdentity)
|
return st.applyRequestRemove(ch.GetAccountRequestRemove(), record)
|
||||||
default:
|
default:
|
||||||
return ErrUnexpectedContentType
|
return ErrUnexpectedContentType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *AclState) applyPermissionChange(ch *aclrecordproto.AclAccountPermissionChange, recordId string, authorIdentity crypto.PubKey) error {
|
func (st *AclState) applyPermissionChange(ch *aclrecordproto.AclAccountPermissionChange, record *AclRecord) error {
|
||||||
chIdentity, err := st.keyStore.PubKeyFromProto(ch.Identity)
|
chIdentity, err := st.keyStore.PubKeyFromProto(ch.Identity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = st.contentValidator.ValidatePermissionChange(ch, authorIdentity)
|
err = st.contentValidator.ValidatePermissionChange(ch, record.Identity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -313,21 +313,21 @@ func (st *AclState) applyPermissionChange(ch *aclrecordproto.AclAccountPermissio
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *AclState) applyInvite(ch *aclrecordproto.AclAccountInvite, recordId string, authorIdentity crypto.PubKey) error {
|
func (st *AclState) applyInvite(ch *aclrecordproto.AclAccountInvite, record *AclRecord) error {
|
||||||
inviteKey, err := st.keyStore.PubKeyFromProto(ch.InviteKey)
|
inviteKey, err := st.keyStore.PubKeyFromProto(ch.InviteKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = st.contentValidator.ValidateInvite(ch, authorIdentity)
|
err = st.contentValidator.ValidateInvite(ch, record.Identity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
st.inviteKeys[recordId] = inviteKey
|
st.inviteKeys[record.Id] = inviteKey
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *AclState) applyInviteRevoke(ch *aclrecordproto.AclAccountInviteRevoke, recordId string, authorIdentity crypto.PubKey) error {
|
func (st *AclState) applyInviteRevoke(ch *aclrecordproto.AclAccountInviteRevoke, record *AclRecord) error {
|
||||||
err := st.contentValidator.ValidateInviteRevoke(ch, authorIdentity)
|
err := st.contentValidator.ValidateInviteRevoke(ch, record.Identity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -335,22 +335,22 @@ func (st *AclState) applyInviteRevoke(ch *aclrecordproto.AclAccountInviteRevoke,
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *AclState) applyRequestJoin(ch *aclrecordproto.AclAccountRequestJoin, recordId string, authorIdentity crypto.PubKey) error {
|
func (st *AclState) applyRequestJoin(ch *aclrecordproto.AclAccountRequestJoin, record *AclRecord) error {
|
||||||
err := st.contentValidator.ValidateRequestJoin(ch, authorIdentity)
|
err := st.contentValidator.ValidateRequestJoin(ch, record.Identity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
st.pendingRequests[mapKeyFromPubKey(authorIdentity)] = recordId
|
st.pendingRequests[mapKeyFromPubKey(record.Identity)] = record.Id
|
||||||
st.requestRecords[recordId] = RequestRecord{
|
st.requestRecords[record.Id] = RequestRecord{
|
||||||
RequestIdentity: authorIdentity,
|
RequestIdentity: record.Identity,
|
||||||
RequestMetadata: ch.Metadata,
|
RequestMetadata: ch.Metadata,
|
||||||
Type: RequestTypeJoin,
|
Type: RequestTypeJoin,
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *AclState) applyRequestAccept(ch *aclrecordproto.AclAccountRequestAccept, recordId string, authorIdentity crypto.PubKey) error {
|
func (st *AclState) applyRequestAccept(ch *aclrecordproto.AclAccountRequestAccept, record *AclRecord) error {
|
||||||
err := st.contentValidator.ValidateRequestAccept(ch, authorIdentity)
|
err := st.contentValidator.ValidateRequestAccept(ch, record.Identity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -358,11 +358,11 @@ func (st *AclState) applyRequestAccept(ch *aclrecordproto.AclAccountRequestAccep
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
record, _ := st.requestRecords[ch.RequestRecordId]
|
requestRecord, _ := st.requestRecords[ch.RequestRecordId]
|
||||||
st.accountStates[mapKeyFromPubKey(acceptIdentity)] = AclAccountState{
|
st.accountStates[mapKeyFromPubKey(acceptIdentity)] = AclAccountState{
|
||||||
PubKey: acceptIdentity,
|
PubKey: acceptIdentity,
|
||||||
Permissions: AclPermissions(ch.Permissions),
|
Permissions: AclPermissions(ch.Permissions),
|
||||||
RequestMetadata: record.RequestMetadata,
|
RequestMetadata: requestRecord.RequestMetadata,
|
||||||
KeyRecordId: st.CurrentReadKeyId(),
|
KeyRecordId: st.CurrentReadKeyId(),
|
||||||
}
|
}
|
||||||
delete(st.pendingRequests, mapKeyFromPubKey(st.requestRecords[ch.RequestRecordId].RequestIdentity))
|
delete(st.pendingRequests, mapKeyFromPubKey(st.requestRecords[ch.RequestRecordId].RequestIdentity))
|
||||||
|
@ -421,8 +421,8 @@ func (st *AclState) applyRequestAccept(ch *aclrecordproto.AclAccountRequestAccep
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *AclState) applyRequestDecline(ch *aclrecordproto.AclAccountRequestDecline, recordId string, authorIdentity crypto.PubKey) error {
|
func (st *AclState) applyRequestDecline(ch *aclrecordproto.AclAccountRequestDecline, record *AclRecord) error {
|
||||||
err := st.contentValidator.ValidateRequestDecline(ch, authorIdentity)
|
err := st.contentValidator.ValidateRequestDecline(ch, record.Identity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -431,21 +431,21 @@ func (st *AclState) applyRequestDecline(ch *aclrecordproto.AclAccountRequestDecl
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *AclState) applyRequestRemove(ch *aclrecordproto.AclAccountRequestRemove, recordId string, authorIdentity crypto.PubKey) error {
|
func (st *AclState) applyRequestRemove(ch *aclrecordproto.AclAccountRequestRemove, record *AclRecord) error {
|
||||||
err := st.contentValidator.ValidateRequestRemove(ch, authorIdentity)
|
err := st.contentValidator.ValidateRequestRemove(ch, record.Identity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
st.requestRecords[recordId] = RequestRecord{
|
st.requestRecords[record.Id] = RequestRecord{
|
||||||
RequestIdentity: authorIdentity,
|
RequestIdentity: record.Identity,
|
||||||
Type: RequestTypeRemove,
|
Type: RequestTypeRemove,
|
||||||
}
|
}
|
||||||
st.pendingRequests[mapKeyFromPubKey(authorIdentity)] = recordId
|
st.pendingRequests[mapKeyFromPubKey(record.Identity)] = record.Id
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *AclState) applyAccountRemove(ch *aclrecordproto.AclAccountRemove, recordId string, authorIdentity crypto.PubKey) error {
|
func (st *AclState) applyAccountRemove(ch *aclrecordproto.AclAccountRemove, record *AclRecord) error {
|
||||||
err := st.contentValidator.ValidateAccountRemove(ch, authorIdentity)
|
err := st.contentValidator.ValidateAccountRemove(ch, record.Identity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -458,17 +458,17 @@ func (st *AclState) applyAccountRemove(ch *aclrecordproto.AclAccountRemove, reco
|
||||||
delete(st.accountStates, idKey)
|
delete(st.accountStates, idKey)
|
||||||
delete(st.pendingRequests, idKey)
|
delete(st.pendingRequests, idKey)
|
||||||
}
|
}
|
||||||
return st.applyReadKeyChange(ch.ReadKeyChange, recordId, authorIdentity, false)
|
return st.applyReadKeyChange(ch.ReadKeyChange, record, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *AclState) applyReadKeyChange(ch *aclrecordproto.AclReadKeyChange, recordId string, authorIdentity crypto.PubKey, validate bool) error {
|
func (st *AclState) applyReadKeyChange(ch *aclrecordproto.AclReadKeyChange, record *AclRecord, validate bool) error {
|
||||||
if validate {
|
if validate {
|
||||||
err := st.contentValidator.ValidateReadKeyChange(ch, authorIdentity)
|
err := st.contentValidator.ValidateReadKeyChange(ch, record.Identity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
st.readKeyChanges = append(st.readKeyChanges, recordId)
|
st.readKeyChanges = append(st.readKeyChanges, record.Id)
|
||||||
mkPubKey, err := st.keyStore.PubKeyFromProto(ch.MetadataPubKey)
|
mkPubKey, err := st.keyStore.PubKeyFromProto(ch.MetadataPubKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -493,7 +493,7 @@ func (st *AclState) applyReadKeyChange(ch *aclrecordproto.AclReadKeyChange, reco
|
||||||
}
|
}
|
||||||
aclKeys.MetadataPrivKey = metadataKey
|
aclKeys.MetadataPrivKey = metadataKey
|
||||||
}
|
}
|
||||||
st.keys[recordId] = aclKeys
|
st.keys[record.Id] = aclKeys
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,12 +86,11 @@ func (fx *aclFixture) inviteAccount(t *testing.T, perms AclPermissions) {
|
||||||
fx.addRec(t, requestAcceptRec)
|
fx.addRec(t, requestAcceptRec)
|
||||||
|
|
||||||
// checking acl state
|
// checking acl state
|
||||||
require.True(t, ownerState.Permissions(ownerState.pubKey).IsOwner())
|
for _, acl := range []*aclList{ownerAcl, accountAcl} {
|
||||||
require.True(t, ownerState.Permissions(accountState.pubKey).CanWrite())
|
require.True(t, acl.AclState().Permissions(ownerAcl.AclState().pubKey).IsOwner())
|
||||||
require.Equal(t, 0, len(ownerState.pendingRequests))
|
require.True(t, acl.AclState().Permissions(acl.AclState().pubKey).CanWrite())
|
||||||
require.Equal(t, 0, len(accountState.pendingRequests))
|
require.Equal(t, 0, len(acl.AclState().pendingRequests))
|
||||||
require.True(t, accountState.Permissions(ownerState.pubKey).IsOwner())
|
}
|
||||||
require.True(t, accountState.Permissions(accountState.pubKey).CanWrite())
|
|
||||||
|
|
||||||
_, err = ownerState.StateAtRecord(requestJoinRec.Id, accountState.pubKey)
|
_, err = ownerState.StateAtRecord(requestJoinRec.Id, accountState.pubKey)
|
||||||
require.Equal(t, ErrNoSuchAccount, err)
|
require.Equal(t, ErrNoSuchAccount, err)
|
||||||
|
@ -295,14 +294,12 @@ func TestAclList_PermissionChange(t *testing.T) {
|
||||||
fx.addRec(t, permissionChangeRec)
|
fx.addRec(t, permissionChangeRec)
|
||||||
|
|
||||||
// checking acl state
|
// checking acl state
|
||||||
require.True(t, ownerState.Permissions(ownerState.pubKey).IsOwner())
|
for _, acl := range []*aclList{fx.ownerAcl, fx.accountAcl} {
|
||||||
require.True(t, ownerState.Permissions(accountState.pubKey) == AclPermissions(aclrecordproto.AclUserPermissions_Writer))
|
require.True(t, acl.AclState().Permissions(ownerState.pubKey).IsOwner())
|
||||||
require.True(t, accountState.Permissions(ownerState.pubKey).IsOwner())
|
require.True(t, acl.AclState().Permissions(accountState.pubKey).CanWrite())
|
||||||
require.True(t, accountState.Permissions(accountState.pubKey) == AclPermissions(aclrecordproto.AclUserPermissions_Writer))
|
require.Equal(t, 0, len(acl.AclState().pendingRequests))
|
||||||
require.NotEmpty(t, ownerState.keys[fx.ownerAcl.Id()])
|
require.NotEmpty(t, acl.AclState().keys[fx.ownerAcl.Id()])
|
||||||
require.NotEmpty(t, accountState.keys[fx.ownerAcl.Id()])
|
}
|
||||||
require.Equal(t, 0, len(ownerState.pendingRequests))
|
|
||||||
require.Equal(t, 0, len(accountState.pendingRequests))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAclList_RequestRemove(t *testing.T) {
|
func TestAclList_RequestRemove(t *testing.T) {
|
||||||
|
@ -337,14 +334,13 @@ func TestAclList_RequestRemove(t *testing.T) {
|
||||||
fx.addRec(t, removeRec)
|
fx.addRec(t, removeRec)
|
||||||
|
|
||||||
// checking acl state
|
// checking acl state
|
||||||
require.True(t, ownerState.Permissions(ownerState.pubKey).IsOwner())
|
for _, acl := range []*aclList{fx.ownerAcl, fx.accountAcl} {
|
||||||
require.True(t, ownerState.Permissions(accountState.pubKey).NoPermissions())
|
require.True(t, acl.AclState().Permissions(ownerState.pubKey).IsOwner())
|
||||||
|
require.True(t, acl.AclState().Permissions(accountState.pubKey).NoPermissions())
|
||||||
|
require.Equal(t, 0, len(acl.AclState().pendingRequests))
|
||||||
|
}
|
||||||
require.True(t, ownerState.keys[removeRec.Id].ReadKey.Equals(newReadKey))
|
require.True(t, ownerState.keys[removeRec.Id].ReadKey.Equals(newReadKey))
|
||||||
require.NotEmpty(t, ownerState.keys[fx.ownerAcl.Id()])
|
require.NotEmpty(t, ownerState.keys[fx.ownerAcl.Id()])
|
||||||
require.Equal(t, 0, len(ownerState.pendingRequests))
|
|
||||||
require.Equal(t, 0, len(accountState.pendingRequests))
|
|
||||||
require.True(t, accountState.Permissions(ownerState.pubKey).IsOwner())
|
|
||||||
require.True(t, accountState.Permissions(accountState.pubKey).NoPermissions())
|
|
||||||
require.Nil(t, accountState.keys[removeRec.Id].MetadataPrivKey)
|
require.Nil(t, accountState.keys[removeRec.Id].MetadataPrivKey)
|
||||||
require.NotNil(t, accountState.keys[removeRec.Id].MetadataPubKey)
|
require.NotNil(t, accountState.keys[removeRec.Id].MetadataPubKey)
|
||||||
require.Nil(t, accountState.keys[removeRec.Id].ReadKey)
|
require.Nil(t, accountState.keys[removeRec.Id].ReadKey)
|
||||||
|
|
|
@ -6,13 +6,14 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type AclRecord struct {
|
type AclRecord struct {
|
||||||
Id string
|
Id string
|
||||||
PrevId string
|
PrevId string
|
||||||
Timestamp int64
|
Timestamp int64
|
||||||
Data []byte
|
AcceptorTimestamp int64
|
||||||
Identity crypto.PubKey
|
Data []byte
|
||||||
Model interface{}
|
Identity crypto.PubKey
|
||||||
Signature []byte
|
Model interface{}
|
||||||
|
Signature []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type RequestRecord struct {
|
type RequestRecord struct {
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
package headupdater
|
package headupdater
|
||||||
|
|
||||||
|
import "github.com/anyproto/any-sync/commonspace/object/acl/list"
|
||||||
|
|
||||||
type HeadUpdater interface {
|
type HeadUpdater interface {
|
||||||
UpdateHeads(id string, heads []string)
|
UpdateHeads(id string, heads []string)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AclUpdater interface {
|
||||||
|
UpdateAcl(aclList list.AclList)
|
||||||
|
}
|
||||||
|
|
|
@ -400,6 +400,18 @@ func (mr *MockSyncAclMockRecorder) Run(arg0 interface{}) *gomock.Call {
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Run", reflect.TypeOf((*MockSyncAcl)(nil).Run), arg0)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Run", reflect.TypeOf((*MockSyncAcl)(nil).Run), arg0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetAclUpdater mocks base method.
|
||||||
|
func (m *MockSyncAcl) SetAclUpdater(arg0 headupdater.AclUpdater) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
m.ctrl.Call(m, "SetAclUpdater", arg0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAclUpdater indicates an expected call of SetAclUpdater.
|
||||||
|
func (mr *MockSyncAclMockRecorder) SetAclUpdater(arg0 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetAclUpdater", reflect.TypeOf((*MockSyncAcl)(nil).SetAclUpdater), arg0)
|
||||||
|
}
|
||||||
|
|
||||||
// SetHeadUpdater mocks base method.
|
// SetHeadUpdater mocks base method.
|
||||||
func (m *MockSyncAcl) SetHeadUpdater(arg0 headupdater.HeadUpdater) {
|
func (m *MockSyncAcl) SetHeadUpdater(arg0 headupdater.HeadUpdater) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
|
|
@ -33,6 +33,7 @@ type SyncAcl interface {
|
||||||
syncobjectgetter.SyncObject
|
syncobjectgetter.SyncObject
|
||||||
SetHeadUpdater(updater headupdater.HeadUpdater)
|
SetHeadUpdater(updater headupdater.HeadUpdater)
|
||||||
SyncWithPeer(ctx context.Context, peerId string) (err error)
|
SyncWithPeer(ctx context.Context, peerId string) (err error)
|
||||||
|
SetAclUpdater(updater headupdater.AclUpdater)
|
||||||
}
|
}
|
||||||
|
|
||||||
func New() SyncAcl {
|
func New() SyncAcl {
|
||||||
|
@ -45,6 +46,13 @@ type syncAcl struct {
|
||||||
syncHandler synchandler.SyncHandler
|
syncHandler synchandler.SyncHandler
|
||||||
headUpdater headupdater.HeadUpdater
|
headUpdater headupdater.HeadUpdater
|
||||||
isClosed bool
|
isClosed bool
|
||||||
|
aclUpdater headupdater.AclUpdater
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *syncAcl) SetAclUpdater(updater headupdater.AclUpdater) {
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
s.aclUpdater = updater
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *syncAcl) Run(ctx context.Context) (err error) {
|
func (s *syncAcl) Run(ctx context.Context) (err error) {
|
||||||
|
@ -97,6 +105,9 @@ func (s *syncAcl) AddRawRecord(rawRec *consensusproto.RawRecordWithId) (err erro
|
||||||
headUpdate := s.syncClient.CreateHeadUpdate(s, []*consensusproto.RawRecordWithId{rawRec})
|
headUpdate := s.syncClient.CreateHeadUpdate(s, []*consensusproto.RawRecordWithId{rawRec})
|
||||||
s.headUpdater.UpdateHeads(s.Id(), []string{rawRec.Id})
|
s.headUpdater.UpdateHeads(s.Id(), []string{rawRec.Id})
|
||||||
s.syncClient.Broadcast(headUpdate)
|
s.syncClient.Broadcast(headUpdate)
|
||||||
|
if s.aclUpdater != nil {
|
||||||
|
s.aclUpdater.UpdateAcl(s)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,6 +122,9 @@ func (s *syncAcl) AddRawRecords(rawRecords []*consensusproto.RawRecordWithId) (e
|
||||||
headUpdate := s.syncClient.CreateHeadUpdate(s, rawRecords)
|
headUpdate := s.syncClient.CreateHeadUpdate(s, rawRecords)
|
||||||
s.headUpdater.UpdateHeads(s.Id(), []string{rawRecords[len(rawRecords)-1].Id})
|
s.headUpdater.UpdateHeads(s.Id(), []string{rawRecords[len(rawRecords)-1].Id})
|
||||||
s.syncClient.Broadcast(headUpdate)
|
s.syncClient.Broadcast(headUpdate)
|
||||||
|
if s.aclUpdater != nil {
|
||||||
|
s.aclUpdater.UpdateAcl(s)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
package settings
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"github.com/anyproto/any-sync/commonspace/deletionstate"
|
|
||||||
"github.com/anyproto/any-sync/commonspace/object/treemanager"
|
|
||||||
"github.com/anyproto/any-sync/commonspace/settings/settingsstate"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type SpaceIdsProvider interface {
|
|
||||||
AllIds() []string
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeletionManager interface {
|
|
||||||
UpdateState(ctx context.Context, state *settingsstate.State) (err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newDeletionManager(
|
|
||||||
spaceId string,
|
|
||||||
settingsId string,
|
|
||||||
isResponsible bool,
|
|
||||||
treeManager treemanager.TreeManager,
|
|
||||||
deletionState deletionstate.ObjectDeletionState,
|
|
||||||
provider SpaceIdsProvider,
|
|
||||||
onSpaceDelete func()) DeletionManager {
|
|
||||||
return &deletionManager{
|
|
||||||
treeManager: treeManager,
|
|
||||||
isResponsible: isResponsible,
|
|
||||||
spaceId: spaceId,
|
|
||||||
settingsId: settingsId,
|
|
||||||
deletionState: deletionState,
|
|
||||||
provider: provider,
|
|
||||||
onSpaceDelete: onSpaceDelete,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type deletionManager struct {
|
|
||||||
deletionState deletionstate.ObjectDeletionState
|
|
||||||
provider SpaceIdsProvider
|
|
||||||
treeManager treemanager.TreeManager
|
|
||||||
spaceId string
|
|
||||||
settingsId string
|
|
||||||
isResponsible bool
|
|
||||||
onSpaceDelete func()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *deletionManager) UpdateState(ctx context.Context, state *settingsstate.State) error {
|
|
||||||
log := log.With(zap.String("spaceId", d.spaceId))
|
|
||||||
d.deletionState.Add(state.DeletedIds)
|
|
||||||
if state.DeleterId == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// we should delete space
|
|
||||||
log.Debug("deleting space")
|
|
||||||
if d.isResponsible {
|
|
||||||
mapIds := map[string]struct{}{}
|
|
||||||
for _, id := range d.provider.AllIds() {
|
|
||||||
if id != d.settingsId {
|
|
||||||
mapIds[id] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
d.deletionState.Add(mapIds)
|
|
||||||
}
|
|
||||||
d.onSpaceDelete()
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
package settings
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"github.com/anyproto/any-sync/commonspace/deletionstate/mock_deletionstate"
|
|
||||||
"github.com/anyproto/any-sync/commonspace/object/treemanager/mock_treemanager"
|
|
||||||
"github.com/anyproto/any-sync/commonspace/settings/mock_settings"
|
|
||||||
"github.com/anyproto/any-sync/commonspace/settings/settingsstate"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"go.uber.org/mock/gomock"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestDeletionManager_UpdateState_NotResponsible(t *testing.T) {
|
|
||||||
ctrl := gomock.NewController(t)
|
|
||||||
defer ctrl.Finish()
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
spaceId := "spaceId"
|
|
||||||
settingsId := "settingsId"
|
|
||||||
state := &settingsstate.State{
|
|
||||||
DeletedIds: map[string]struct{}{"id": {}},
|
|
||||||
DeleterId: "deleterId",
|
|
||||||
}
|
|
||||||
deleted := false
|
|
||||||
onDeleted := func() {
|
|
||||||
deleted = true
|
|
||||||
}
|
|
||||||
delState := mock_deletionstate.NewMockObjectDeletionState(ctrl)
|
|
||||||
treeManager := mock_treemanager.NewMockTreeManager(ctrl)
|
|
||||||
|
|
||||||
delState.EXPECT().Add(state.DeletedIds)
|
|
||||||
|
|
||||||
delManager := newDeletionManager(spaceId,
|
|
||||||
settingsId,
|
|
||||||
false,
|
|
||||||
treeManager,
|
|
||||||
delState,
|
|
||||||
nil,
|
|
||||||
onDeleted)
|
|
||||||
err := delManager.UpdateState(ctx, state)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.True(t, deleted)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDeletionManager_UpdateState_Responsible(t *testing.T) {
|
|
||||||
ctrl := gomock.NewController(t)
|
|
||||||
defer ctrl.Finish()
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
spaceId := "spaceId"
|
|
||||||
settingsId := "settingsId"
|
|
||||||
state := &settingsstate.State{
|
|
||||||
DeletedIds: map[string]struct{}{"id": struct{}{}},
|
|
||||||
DeleterId: "deleterId",
|
|
||||||
}
|
|
||||||
deleted := false
|
|
||||||
onDeleted := func() {
|
|
||||||
deleted = true
|
|
||||||
}
|
|
||||||
delState := mock_deletionstate.NewMockObjectDeletionState(ctrl)
|
|
||||||
treeManager := mock_treemanager.NewMockTreeManager(ctrl)
|
|
||||||
provider := mock_settings.NewMockSpaceIdsProvider(ctrl)
|
|
||||||
|
|
||||||
delState.EXPECT().Add(state.DeletedIds)
|
|
||||||
provider.EXPECT().AllIds().Return([]string{"id", "otherId", settingsId})
|
|
||||||
delState.EXPECT().Add(map[string]struct{}{"id": {}, "otherId": {}})
|
|
||||||
delManager := newDeletionManager(spaceId,
|
|
||||||
settingsId,
|
|
||||||
true,
|
|
||||||
treeManager,
|
|
||||||
delState,
|
|
||||||
provider,
|
|
||||||
onDeleted)
|
|
||||||
|
|
||||||
err := delManager.UpdateState(ctx, state)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.True(t, deleted)
|
|
||||||
}
|
|
|
@ -2,17 +2,14 @@ package settings
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/anyproto/any-sync/commonspace/deletionmanager"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/anyproto/any-sync/accountservice"
|
"github.com/anyproto/any-sync/accountservice"
|
||||||
"github.com/anyproto/any-sync/app"
|
"github.com/anyproto/any-sync/app"
|
||||||
"github.com/anyproto/any-sync/commonspace/deletionstate"
|
|
||||||
"github.com/anyproto/any-sync/commonspace/headsync"
|
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
|
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/synctree"
|
"github.com/anyproto/any-sync/commonspace/object/tree/synctree"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/synctree/updatelistener"
|
"github.com/anyproto/any-sync/commonspace/object/tree/synctree/updatelistener"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
|
|
||||||
"github.com/anyproto/any-sync/commonspace/object/treemanager"
|
|
||||||
"github.com/anyproto/any-sync/commonspace/objecttreebuilder"
|
"github.com/anyproto/any-sync/commonspace/objecttreebuilder"
|
||||||
"github.com/anyproto/any-sync/commonspace/spacestate"
|
"github.com/anyproto/any-sync/commonspace/spacestate"
|
||||||
"github.com/anyproto/any-sync/commonspace/spacestorage"
|
"github.com/anyproto/any-sync/commonspace/spacestorage"
|
||||||
|
@ -24,8 +21,6 @@ const CName = "common.commonspace.settings"
|
||||||
|
|
||||||
type Settings interface {
|
type Settings interface {
|
||||||
DeleteTree(ctx context.Context, id string) (err error)
|
DeleteTree(ctx context.Context, id string) (err error)
|
||||||
SpaceDeleteRawChange(ctx context.Context) (raw *treechangeproto.RawTreeChangeWithId, err error)
|
|
||||||
DeleteSpace(ctx context.Context, deleteChange *treechangeproto.RawTreeChangeWithId) (err error)
|
|
||||||
SettingsObject() SettingsObject
|
SettingsObject() SettingsObject
|
||||||
app.ComponentRunnable
|
app.ComponentRunnable
|
||||||
}
|
}
|
||||||
|
@ -36,11 +31,8 @@ func New() Settings {
|
||||||
|
|
||||||
type settings struct {
|
type settings struct {
|
||||||
account accountservice.Service
|
account accountservice.Service
|
||||||
treeManager treemanager.TreeManager
|
|
||||||
storage spacestorage.SpaceStorage
|
storage spacestorage.SpaceStorage
|
||||||
configuration nodeconf.NodeConf
|
configuration nodeconf.NodeConf
|
||||||
deletionState deletionstate.ObjectDeletionState
|
|
||||||
headsync headsync.HeadSync
|
|
||||||
treeBuilder objecttreebuilder.TreeBuilderComponent
|
treeBuilder objecttreebuilder.TreeBuilderComponent
|
||||||
spaceIsDeleted *atomic.Bool
|
spaceIsDeleted *atomic.Bool
|
||||||
|
|
||||||
|
@ -49,12 +41,8 @@ type settings struct {
|
||||||
|
|
||||||
func (s *settings) Init(a *app.App) (err error) {
|
func (s *settings) Init(a *app.App) (err error) {
|
||||||
s.account = a.MustComponent(accountservice.CName).(accountservice.Service)
|
s.account = a.MustComponent(accountservice.CName).(accountservice.Service)
|
||||||
s.treeManager = app.MustComponent[treemanager.TreeManager](a)
|
|
||||||
s.headsync = a.MustComponent(headsync.CName).(headsync.HeadSync)
|
|
||||||
s.configuration = a.MustComponent(nodeconf.CName).(nodeconf.NodeConf)
|
s.configuration = a.MustComponent(nodeconf.CName).(nodeconf.NodeConf)
|
||||||
s.deletionState = a.MustComponent(deletionstate.CName).(deletionstate.ObjectDeletionState)
|
|
||||||
s.treeBuilder = a.MustComponent(objecttreebuilder.CName).(objecttreebuilder.TreeBuilderComponent)
|
s.treeBuilder = a.MustComponent(objecttreebuilder.CName).(objecttreebuilder.TreeBuilderComponent)
|
||||||
|
|
||||||
sharedState := a.MustComponent(spacestate.CName).(*spacestate.SpaceState)
|
sharedState := a.MustComponent(spacestate.CName).(*spacestate.SpaceState)
|
||||||
s.storage = a.MustComponent(spacestorage.CName).(spacestorage.SpaceStorage)
|
s.storage = a.MustComponent(spacestorage.CName).(spacestorage.SpaceStorage)
|
||||||
s.spaceIsDeleted = sharedState.SpaceIsDeleted
|
s.spaceIsDeleted = sharedState.SpaceIsDeleted
|
||||||
|
@ -74,12 +62,9 @@ func (s *settings) Init(a *app.App) (err error) {
|
||||||
return
|
return
|
||||||
},
|
},
|
||||||
Account: s.account,
|
Account: s.account,
|
||||||
TreeManager: s.treeManager,
|
|
||||||
Store: s.storage,
|
Store: s.storage,
|
||||||
Configuration: s.configuration,
|
Configuration: s.configuration,
|
||||||
DeletionState: s.deletionState,
|
DelManager: a.MustComponent(deletionmanager.CName).(deletionmanager.DeletionManager),
|
||||||
Provider: s.headsync,
|
|
||||||
OnSpaceDelete: s.onSpaceDelete,
|
|
||||||
}
|
}
|
||||||
s.settingsObject = NewSettingsObject(deps, sharedState.SpaceId)
|
s.settingsObject = NewSettingsObject(deps, sharedState.SpaceId)
|
||||||
return nil
|
return nil
|
||||||
|
@ -101,22 +86,6 @@ func (s *settings) DeleteTree(ctx context.Context, id string) (err error) {
|
||||||
return s.settingsObject.DeleteObject(id)
|
return s.settingsObject.DeleteObject(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *settings) SpaceDeleteRawChange(ctx context.Context) (raw *treechangeproto.RawTreeChangeWithId, err error) {
|
|
||||||
return s.settingsObject.SpaceDeleteRawChange()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *settings) DeleteSpace(ctx context.Context, deleteChange *treechangeproto.RawTreeChangeWithId) (err error) {
|
|
||||||
return s.settingsObject.DeleteSpace(ctx, deleteChange)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *settings) onSpaceDelete() {
|
|
||||||
err := s.storage.SetSpaceDeleted()
|
|
||||||
if err != nil {
|
|
||||||
log.Warn("failed to set space deleted")
|
|
||||||
}
|
|
||||||
s.spaceIsDeleted.Swap(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *settings) SettingsObject() SettingsObject {
|
func (s *settings) SettingsObject() SettingsObject {
|
||||||
return s.settingsObject
|
return s.settingsObject
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
//go:generate mockgen -destination mock_settings/mock_settings.go github.com/anyproto/any-sync/commonspace/settings DeletionManager,Deleter,SpaceIdsProvider
|
|
||||||
package settings
|
package settings
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/anyproto/any-sync/commonspace/deletionstate"
|
"github.com/anyproto/any-sync/commonspace/deletionmanager"
|
||||||
"github.com/anyproto/any-sync/util/crypto"
|
"github.com/anyproto/any-sync/util/crypto"
|
||||||
|
|
||||||
"github.com/anyproto/any-sync/accountservice"
|
"github.com/anyproto/any-sync/accountservice"
|
||||||
|
@ -21,7 +20,6 @@ import (
|
||||||
"github.com/anyproto/any-sync/nodeconf"
|
"github.com/anyproto/any-sync/nodeconf"
|
||||||
"github.com/gogo/protobuf/proto"
|
"github.com/gogo/protobuf/proto"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"golang.org/x/exp/slices"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var log = logger.NewNamed("common.commonspace.settings")
|
var log = logger.NewNamed("common.commonspace.settings")
|
||||||
|
@ -30,8 +28,6 @@ type SettingsObject interface {
|
||||||
synctree.SyncTree
|
synctree.SyncTree
|
||||||
Init(ctx context.Context) (err error)
|
Init(ctx context.Context) (err error)
|
||||||
DeleteObject(id string) (err error)
|
DeleteObject(id string) (err error)
|
||||||
DeleteSpace(ctx context.Context, raw *treechangeproto.RawTreeChangeWithId) (err error)
|
|
||||||
SpaceDeleteRawChange() (raw *treechangeproto.RawTreeChangeWithId, err error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -60,56 +56,30 @@ type Deps struct {
|
||||||
TreeManager treemanager.TreeManager
|
TreeManager treemanager.TreeManager
|
||||||
Store spacestorage.SpaceStorage
|
Store spacestorage.SpaceStorage
|
||||||
Configuration nodeconf.NodeConf
|
Configuration nodeconf.NodeConf
|
||||||
DeletionState deletionstate.ObjectDeletionState
|
DelManager deletionmanager.DeletionManager
|
||||||
Provider SpaceIdsProvider
|
|
||||||
OnSpaceDelete func()
|
|
||||||
// testing dependencies
|
// testing dependencies
|
||||||
builder settingsstate.StateBuilder
|
builder settingsstate.StateBuilder
|
||||||
del Deleter
|
|
||||||
delManager DeletionManager
|
|
||||||
changeFactory settingsstate.ChangeFactory
|
changeFactory settingsstate.ChangeFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
type settingsObject struct {
|
type settingsObject struct {
|
||||||
synctree.SyncTree
|
synctree.SyncTree
|
||||||
account accountservice.Service
|
account accountservice.Service
|
||||||
spaceId string
|
spaceId string
|
||||||
treeManager treemanager.TreeManager
|
store spacestorage.SpaceStorage
|
||||||
store spacestorage.SpaceStorage
|
builder settingsstate.StateBuilder
|
||||||
builder settingsstate.StateBuilder
|
buildFunc BuildTreeFunc
|
||||||
buildFunc BuildTreeFunc
|
|
||||||
loop *deleteLoop
|
|
||||||
|
|
||||||
state *settingsstate.State
|
state *settingsstate.State
|
||||||
deletionState deletionstate.ObjectDeletionState
|
deletionManager deletionmanager.DeletionManager
|
||||||
deletionManager DeletionManager
|
|
||||||
changeFactory settingsstate.ChangeFactory
|
changeFactory settingsstate.ChangeFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSettingsObject(deps Deps, spaceId string) (obj SettingsObject) {
|
func NewSettingsObject(deps Deps, spaceId string) (obj SettingsObject) {
|
||||||
var (
|
var (
|
||||||
deleter Deleter
|
builder settingsstate.StateBuilder
|
||||||
deletionManager DeletionManager
|
changeFactory settingsstate.ChangeFactory
|
||||||
builder settingsstate.StateBuilder
|
|
||||||
changeFactory settingsstate.ChangeFactory
|
|
||||||
)
|
)
|
||||||
if deps.del == nil {
|
|
||||||
deleter = newDeleter(deps.Store, deps.DeletionState, deps.TreeManager)
|
|
||||||
} else {
|
|
||||||
deleter = deps.del
|
|
||||||
}
|
|
||||||
if deps.delManager == nil {
|
|
||||||
deletionManager = newDeletionManager(
|
|
||||||
spaceId,
|
|
||||||
deps.Store.SpaceSettingsId(),
|
|
||||||
deps.Configuration.IsResponsible(spaceId),
|
|
||||||
deps.TreeManager,
|
|
||||||
deps.DeletionState,
|
|
||||||
deps.Provider,
|
|
||||||
deps.OnSpaceDelete)
|
|
||||||
} else {
|
|
||||||
deletionManager = deps.delManager
|
|
||||||
}
|
|
||||||
if deps.builder == nil {
|
if deps.builder == nil {
|
||||||
builder = settingsstate.NewStateBuilder()
|
builder = settingsstate.NewStateBuilder()
|
||||||
} else {
|
} else {
|
||||||
|
@ -121,23 +91,13 @@ func NewSettingsObject(deps Deps, spaceId string) (obj SettingsObject) {
|
||||||
changeFactory = deps.changeFactory
|
changeFactory = deps.changeFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
loop := newDeleteLoop(func() {
|
|
||||||
deleter.Delete()
|
|
||||||
})
|
|
||||||
deps.DeletionState.AddObserver(func(ids []string) {
|
|
||||||
loop.notify()
|
|
||||||
})
|
|
||||||
|
|
||||||
s := &settingsObject{
|
s := &settingsObject{
|
||||||
loop: loop,
|
|
||||||
spaceId: spaceId,
|
spaceId: spaceId,
|
||||||
account: deps.Account,
|
account: deps.Account,
|
||||||
deletionState: deps.DeletionState,
|
|
||||||
treeManager: deps.TreeManager,
|
|
||||||
store: deps.Store,
|
store: deps.Store,
|
||||||
buildFunc: deps.BuildFunc,
|
buildFunc: deps.BuildFunc,
|
||||||
builder: builder,
|
builder: builder,
|
||||||
deletionManager: deletionManager,
|
deletionManager: deps.DelManager,
|
||||||
changeFactory: changeFactory,
|
changeFactory: changeFactory,
|
||||||
}
|
}
|
||||||
obj = s
|
obj = s
|
||||||
|
@ -151,7 +111,6 @@ func (s *settingsObject) updateIds(tr objecttree.ObjectTree) {
|
||||||
log.Error("failed to build state", zap.Error(err))
|
log.Error("failed to build state", zap.Error(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Debug("updating object state", zap.String("deleted by", s.state.DeleterId))
|
|
||||||
if err = s.deletionManager.UpdateState(context.Background(), s.state); err != nil {
|
if err = s.deletionManager.UpdateState(context.Background(), s.state); err != nil {
|
||||||
log.Error("failed to update state", zap.Error(err))
|
log.Error("failed to update state", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
@ -180,7 +139,6 @@ func (s *settingsObject) Init(ctx context.Context) (err error) {
|
||||||
if err = s.checkHistoryState(ctx); err != nil {
|
if err = s.checkHistoryState(ctx); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.loop.Run()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,48 +165,9 @@ func (s *settingsObject) checkHistoryState(ctx context.Context) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *settingsObject) Close() error {
|
func (s *settingsObject) Close() error {
|
||||||
s.loop.Close()
|
|
||||||
return s.SyncTree.Close()
|
return s.SyncTree.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *settingsObject) DeleteSpace(ctx context.Context, raw *treechangeproto.RawTreeChangeWithId) (err error) {
|
|
||||||
s.Lock()
|
|
||||||
defer s.Unlock()
|
|
||||||
defer func() {
|
|
||||||
log.Debug("finished adding delete change", zap.Error(err))
|
|
||||||
}()
|
|
||||||
err = s.verifyDeleteSpace(raw)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
res, err := s.AddRawChanges(ctx, objecttree.RawChangesPayload{
|
|
||||||
NewHeads: []string{raw.Id},
|
|
||||||
RawChanges: []*treechangeproto.RawTreeChangeWithId{raw},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !slices.Contains(res.Heads, raw.Id) {
|
|
||||||
err = ErrCantDeleteSpace
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *settingsObject) SpaceDeleteRawChange() (raw *treechangeproto.RawTreeChangeWithId, err error) {
|
|
||||||
accountData := s.account.Account()
|
|
||||||
data, err := s.changeFactory.CreateSpaceDeleteChange(accountData.PeerId, s.state, false)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return s.PrepareChange(objecttree.SignableChangeContent{
|
|
||||||
Data: data,
|
|
||||||
Key: accountData.SignKey,
|
|
||||||
IsSnapshot: false,
|
|
||||||
IsEncrypted: false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *settingsObject) DeleteObject(id string) (err error) {
|
func (s *settingsObject) DeleteObject(id string) (err error) {
|
||||||
s.Lock()
|
s.Lock()
|
||||||
defer s.Unlock()
|
defer s.Unlock()
|
||||||
|
|
|
@ -3,16 +3,14 @@ package settings
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/anyproto/any-sync/accountservice/mock_accountservice"
|
"github.com/anyproto/any-sync/accountservice/mock_accountservice"
|
||||||
"github.com/anyproto/any-sync/commonspace/deletionstate/mock_deletionstate"
|
"github.com/anyproto/any-sync/commonspace/deletionmanager/mock_deletionmanager"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/accountdata"
|
"github.com/anyproto/any-sync/commonspace/object/accountdata"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
|
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree/mock_objecttree"
|
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree/mock_objecttree"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/synctree"
|
"github.com/anyproto/any-sync/commonspace/object/tree/synctree"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/synctree/mock_synctree"
|
"github.com/anyproto/any-sync/commonspace/object/tree/synctree/mock_synctree"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/synctree/updatelistener"
|
"github.com/anyproto/any-sync/commonspace/object/tree/synctree/updatelistener"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
|
|
||||||
"github.com/anyproto/any-sync/commonspace/object/treemanager/mock_treemanager"
|
"github.com/anyproto/any-sync/commonspace/object/treemanager/mock_treemanager"
|
||||||
"github.com/anyproto/any-sync/commonspace/settings/mock_settings"
|
|
||||||
"github.com/anyproto/any-sync/commonspace/settings/settingsstate"
|
"github.com/anyproto/any-sync/commonspace/settings/settingsstate"
|
||||||
"github.com/anyproto/any-sync/commonspace/settings/settingsstate/mock_settingsstate"
|
"github.com/anyproto/any-sync/commonspace/settings/settingsstate/mock_settingsstate"
|
||||||
"github.com/anyproto/any-sync/commonspace/spacestorage/mock_spacestorage"
|
"github.com/anyproto/any-sync/commonspace/spacestorage/mock_spacestorage"
|
||||||
|
@ -50,12 +48,10 @@ type settingsFixture struct {
|
||||||
treeManager *mock_treemanager.MockTreeManager
|
treeManager *mock_treemanager.MockTreeManager
|
||||||
spaceStorage *mock_spacestorage.MockSpaceStorage
|
spaceStorage *mock_spacestorage.MockSpaceStorage
|
||||||
stateBuilder *mock_settingsstate.MockStateBuilder
|
stateBuilder *mock_settingsstate.MockStateBuilder
|
||||||
deletionManager *mock_settings.MockDeletionManager
|
deletionManager *mock_deletionmanager.MockDeletionManager
|
||||||
changeFactory *mock_settingsstate.MockChangeFactory
|
changeFactory *mock_settingsstate.MockChangeFactory
|
||||||
deleter *mock_settings.MockDeleter
|
|
||||||
syncTree *mock_synctree.MockSyncTree
|
syncTree *mock_synctree.MockSyncTree
|
||||||
historyTree *mock_objecttree.MockObjectTree
|
historyTree *mock_objecttree.MockObjectTree
|
||||||
delState *mock_deletionstate.MockObjectDeletionState
|
|
||||||
account *mock_accountservice.MockService
|
account *mock_accountservice.MockService
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,15 +63,11 @@ func newSettingsFixture(t *testing.T) *settingsFixture {
|
||||||
acc := mock_accountservice.NewMockService(ctrl)
|
acc := mock_accountservice.NewMockService(ctrl)
|
||||||
treeManager := mock_treemanager.NewMockTreeManager(ctrl)
|
treeManager := mock_treemanager.NewMockTreeManager(ctrl)
|
||||||
st := mock_spacestorage.NewMockSpaceStorage(ctrl)
|
st := mock_spacestorage.NewMockSpaceStorage(ctrl)
|
||||||
delState := mock_deletionstate.NewMockObjectDeletionState(ctrl)
|
delManager := mock_deletionmanager.NewMockDeletionManager(ctrl)
|
||||||
delManager := mock_settings.NewMockDeletionManager(ctrl)
|
|
||||||
stateBuilder := mock_settingsstate.NewMockStateBuilder(ctrl)
|
stateBuilder := mock_settingsstate.NewMockStateBuilder(ctrl)
|
||||||
changeFactory := mock_settingsstate.NewMockChangeFactory(ctrl)
|
changeFactory := mock_settingsstate.NewMockChangeFactory(ctrl)
|
||||||
syncTree := mock_synctree.NewMockSyncTree(ctrl)
|
syncTree := mock_synctree.NewMockSyncTree(ctrl)
|
||||||
historyTree := mock_objecttree.NewMockObjectTree(ctrl)
|
historyTree := mock_objecttree.NewMockObjectTree(ctrl)
|
||||||
del := mock_settings.NewMockDeleter(ctrl)
|
|
||||||
|
|
||||||
delState.EXPECT().AddObserver(gomock.Any())
|
|
||||||
|
|
||||||
buildFunc := BuildTreeFunc(func(ctx context.Context, id string, listener updatelistener.UpdateListener) (synctree.SyncTree, error) {
|
buildFunc := BuildTreeFunc(func(ctx context.Context, id string, listener updatelistener.UpdateListener) (synctree.SyncTree, error) {
|
||||||
require.Equal(t, objectId, id)
|
require.Equal(t, objectId, id)
|
||||||
|
@ -90,11 +82,9 @@ func newSettingsFixture(t *testing.T) *settingsFixture {
|
||||||
Account: acc,
|
Account: acc,
|
||||||
TreeManager: treeManager,
|
TreeManager: treeManager,
|
||||||
Store: st,
|
Store: st,
|
||||||
DeletionState: delState,
|
DelManager: delManager,
|
||||||
delManager: delManager,
|
|
||||||
changeFactory: changeFactory,
|
changeFactory: changeFactory,
|
||||||
builder: stateBuilder,
|
builder: stateBuilder,
|
||||||
del: del,
|
|
||||||
}
|
}
|
||||||
doc := NewSettingsObject(deps, spaceId).(*settingsObject)
|
doc := NewSettingsObject(deps, spaceId).(*settingsObject)
|
||||||
return &settingsFixture{
|
return &settingsFixture{
|
||||||
|
@ -107,17 +97,14 @@ func newSettingsFixture(t *testing.T) *settingsFixture {
|
||||||
stateBuilder: stateBuilder,
|
stateBuilder: stateBuilder,
|
||||||
changeFactory: changeFactory,
|
changeFactory: changeFactory,
|
||||||
deletionManager: delManager,
|
deletionManager: delManager,
|
||||||
deleter: del,
|
|
||||||
syncTree: syncTree,
|
syncTree: syncTree,
|
||||||
account: acc,
|
account: acc,
|
||||||
delState: delState,
|
|
||||||
historyTree: historyTree,
|
historyTree: historyTree,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fx *settingsFixture) init(t *testing.T) {
|
func (fx *settingsFixture) init(t *testing.T) {
|
||||||
fx.spaceStorage.EXPECT().SpaceSettingsId().Return(fx.docId)
|
fx.spaceStorage.EXPECT().SpaceSettingsId().Return(fx.docId)
|
||||||
fx.deleter.EXPECT().Delete()
|
|
||||||
fx.stateBuilder.EXPECT().Build(fx.historyTree, nil).Return(&settingsstate.State{}, nil)
|
fx.stateBuilder.EXPECT().Build(fx.historyTree, nil).Return(&settingsstate.State{}, nil)
|
||||||
fx.doc.state = &settingsstate.State{}
|
fx.doc.state = &settingsstate.State{}
|
||||||
|
|
||||||
|
@ -235,64 +222,3 @@ func TestSettingsObject_Update(t *testing.T) {
|
||||||
|
|
||||||
fx.doc.Update(fx.doc)
|
fx.doc.Update(fx.doc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSettingsObject_DeleteSpace(t *testing.T) {
|
|
||||||
fx := newSettingsFixture(t)
|
|
||||||
defer fx.stop(t)
|
|
||||||
|
|
||||||
fx.init(t)
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
|
|
||||||
deleterId := "delId"
|
|
||||||
rawCh := &treechangeproto.RawTreeChangeWithId{
|
|
||||||
RawChange: []byte{1},
|
|
||||||
Id: "id",
|
|
||||||
}
|
|
||||||
changeFactory := settingsstate.NewChangeFactory()
|
|
||||||
delChange, _ := changeFactory.CreateSpaceDeleteChange(deleterId, &settingsstate.State{}, false)
|
|
||||||
|
|
||||||
fx.syncTree.EXPECT().UnpackChange(rawCh).Return(delChange, nil)
|
|
||||||
fx.syncTree.EXPECT().AddRawChanges(gomock.Any(), objecttree.RawChangesPayload{
|
|
||||||
NewHeads: []string{rawCh.Id},
|
|
||||||
RawChanges: []*treechangeproto.RawTreeChangeWithId{rawCh},
|
|
||||||
}).Return(objecttree.AddResult{
|
|
||||||
Heads: []string{rawCh.Id},
|
|
||||||
}, nil)
|
|
||||||
|
|
||||||
err := fx.doc.DeleteSpace(context.Background(), rawCh)
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSettingsObject_DeleteSpaceIncorrectChange(t *testing.T) {
|
|
||||||
fx := newSettingsFixture(t)
|
|
||||||
defer fx.stop(t)
|
|
||||||
|
|
||||||
fx.init(t)
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
|
|
||||||
t.Run("incorrect change type", func(t *testing.T) {
|
|
||||||
rawCh := &treechangeproto.RawTreeChangeWithId{
|
|
||||||
RawChange: []byte{1},
|
|
||||||
Id: "id",
|
|
||||||
}
|
|
||||||
changeFactory := settingsstate.NewChangeFactory()
|
|
||||||
delChange, _ := changeFactory.CreateObjectDeleteChange("otherId", &settingsstate.State{}, false)
|
|
||||||
|
|
||||||
fx.syncTree.EXPECT().UnpackChange(rawCh).Return(delChange, nil)
|
|
||||||
err := fx.doc.DeleteSpace(context.Background(), rawCh)
|
|
||||||
require.NotNil(t, err)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("empty peer", func(t *testing.T) {
|
|
||||||
rawCh := &treechangeproto.RawTreeChangeWithId{
|
|
||||||
RawChange: []byte{1},
|
|
||||||
Id: "id",
|
|
||||||
}
|
|
||||||
changeFactory := settingsstate.NewChangeFactory()
|
|
||||||
delChange, _ := changeFactory.CreateSpaceDeleteChange("", &settingsstate.State{}, false)
|
|
||||||
|
|
||||||
fx.syncTree.EXPECT().UnpackChange(rawCh).Return(delChange, nil)
|
|
||||||
err := fx.doc.DeleteSpace(context.Background(), rawCh)
|
|
||||||
require.NotNil(t, err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
|
|
||||||
type ChangeFactory interface {
|
type ChangeFactory interface {
|
||||||
CreateObjectDeleteChange(id string, state *State, isSnapshot bool) (res []byte, err error)
|
CreateObjectDeleteChange(id string, state *State, isSnapshot bool) (res []byte, err error)
|
||||||
CreateSpaceDeleteChange(peerId string, state *State, isSnapshot bool) (res []byte, err error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewChangeFactory() ChangeFactory {
|
func NewChangeFactory() ChangeFactory {
|
||||||
|
@ -26,44 +25,23 @@ func (c *changeFactory) CreateObjectDeleteChange(id string, state *State, isSnap
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if isSnapshot {
|
if isSnapshot {
|
||||||
change.Snapshot = c.makeSnapshot(state, id, "")
|
change.Snapshot = c.makeSnapshot(state, id)
|
||||||
}
|
}
|
||||||
res, err = change.Marshal()
|
res, err = change.Marshal()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *changeFactory) CreateSpaceDeleteChange(peerId string, state *State, isSnapshot bool) (res []byte, err error) {
|
func (c *changeFactory) makeSnapshot(state *State, objectId string) *spacesyncproto.SpaceSettingsSnapshot {
|
||||||
content := &spacesyncproto.SpaceSettingsContent_SpaceDelete{
|
|
||||||
SpaceDelete: &spacesyncproto.SpaceDelete{DeleterPeerId: peerId},
|
|
||||||
}
|
|
||||||
change := &spacesyncproto.SettingsData{
|
|
||||||
Content: []*spacesyncproto.SpaceSettingsContent{
|
|
||||||
{Value: content},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if isSnapshot {
|
|
||||||
change.Snapshot = c.makeSnapshot(state, "", peerId)
|
|
||||||
}
|
|
||||||
res, err = change.Marshal()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *changeFactory) makeSnapshot(state *State, objectId, deleterPeer string) *spacesyncproto.SpaceSettingsSnapshot {
|
|
||||||
var (
|
var (
|
||||||
deletedIds = make([]string, 0, len(state.DeletedIds)+1)
|
deletedIds = make([]string, 0, len(state.DeletedIds)+1)
|
||||||
deleterId = state.DeleterId
|
|
||||||
)
|
)
|
||||||
if objectId != "" {
|
if objectId != "" {
|
||||||
deletedIds = append(deletedIds, objectId)
|
deletedIds = append(deletedIds, objectId)
|
||||||
}
|
}
|
||||||
if deleterPeer != "" {
|
|
||||||
deleterId = deleterPeer
|
|
||||||
}
|
|
||||||
for id := range state.DeletedIds {
|
for id := range state.DeletedIds {
|
||||||
deletedIds = append(deletedIds, id)
|
deletedIds = append(deletedIds, id)
|
||||||
}
|
}
|
||||||
return &spacesyncproto.SpaceSettingsSnapshot{
|
return &spacesyncproto.SpaceSettingsSnapshot{
|
||||||
DeletedIds: deletedIds,
|
DeletedIds: deletedIds,
|
||||||
DeleterPeerId: deleterId,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ func TestChangeFactory_CreateObjectDeleteChange(t *testing.T) {
|
||||||
factory := NewChangeFactory()
|
factory := NewChangeFactory()
|
||||||
state := &State{
|
state := &State{
|
||||||
DeletedIds: map[string]struct{}{"1": {}, "2": {}},
|
DeletedIds: map[string]struct{}{"1": {}, "2": {}},
|
||||||
DeleterId: "del",
|
|
||||||
}
|
}
|
||||||
marshalled, err := factory.CreateObjectDeleteChange("3", state, false)
|
marshalled, err := factory.CreateObjectDeleteChange("3", state, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -29,34 +28,7 @@ func TestChangeFactory_CreateObjectDeleteChange(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
slices.Sort(data.Snapshot.DeletedIds)
|
slices.Sort(data.Snapshot.DeletedIds)
|
||||||
require.Equal(t, &spacesyncproto.SpaceSettingsSnapshot{
|
require.Equal(t, &spacesyncproto.SpaceSettingsSnapshot{
|
||||||
DeletedIds: []string{"1", "2", "3"},
|
DeletedIds: []string{"1", "2", "3"},
|
||||||
DeleterPeerId: "del",
|
|
||||||
}, data.Snapshot)
|
}, data.Snapshot)
|
||||||
require.Equal(t, "3", data.Content[0].Value.(*spacesyncproto.SpaceSettingsContent_ObjectDelete).ObjectDelete.Id)
|
require.Equal(t, "3", data.Content[0].Value.(*spacesyncproto.SpaceSettingsContent_ObjectDelete).ObjectDelete.Id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestChangeFactory_CreateSpaceDeleteChange(t *testing.T) {
|
|
||||||
factory := NewChangeFactory()
|
|
||||||
state := &State{
|
|
||||||
DeletedIds: map[string]struct{}{"1": {}, "2": {}},
|
|
||||||
}
|
|
||||||
marshalled, err := factory.CreateSpaceDeleteChange("del", state, false)
|
|
||||||
require.NoError(t, err)
|
|
||||||
data := &spacesyncproto.SettingsData{}
|
|
||||||
err = proto.Unmarshal(marshalled, data)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Nil(t, data.Snapshot)
|
|
||||||
require.Equal(t, "del", data.Content[0].Value.(*spacesyncproto.SpaceSettingsContent_SpaceDelete).SpaceDelete.DeleterPeerId)
|
|
||||||
|
|
||||||
marshalled, err = factory.CreateSpaceDeleteChange("del", state, true)
|
|
||||||
require.NoError(t, err)
|
|
||||||
data = &spacesyncproto.SettingsData{}
|
|
||||||
err = proto.Unmarshal(marshalled, data)
|
|
||||||
require.NoError(t, err)
|
|
||||||
slices.Sort(data.Snapshot.DeletedIds)
|
|
||||||
require.Equal(t, &spacesyncproto.SpaceSettingsSnapshot{
|
|
||||||
DeletedIds: []string{"1", "2"},
|
|
||||||
DeleterPeerId: "del",
|
|
||||||
}, data.Snapshot)
|
|
||||||
require.Equal(t, "del", data.Content[0].Value.(*spacesyncproto.SpaceSettingsContent_SpaceDelete).SpaceDelete.DeleterPeerId)
|
|
||||||
}
|
|
||||||
|
|
|
@ -87,18 +87,3 @@ func (mr *MockChangeFactoryMockRecorder) CreateObjectDeleteChange(arg0, arg1, ar
|
||||||
mr.mock.ctrl.T.Helper()
|
mr.mock.ctrl.T.Helper()
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateObjectDeleteChange", reflect.TypeOf((*MockChangeFactory)(nil).CreateObjectDeleteChange), arg0, arg1, arg2)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateObjectDeleteChange", reflect.TypeOf((*MockChangeFactory)(nil).CreateObjectDeleteChange), arg0, arg1, arg2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateSpaceDeleteChange mocks base method.
|
|
||||||
func (m *MockChangeFactory) CreateSpaceDeleteChange(arg0 string, arg1 *settingsstate.State, arg2 bool) ([]byte, error) {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "CreateSpaceDeleteChange", arg0, arg1, arg2)
|
|
||||||
ret0, _ := ret[0].([]byte)
|
|
||||||
ret1, _ := ret[1].(error)
|
|
||||||
return ret0, ret1
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateSpaceDeleteChange indicates an expected call of CreateSpaceDeleteChange.
|
|
||||||
func (mr *MockChangeFactoryMockRecorder) CreateSpaceDeleteChange(arg0, arg1, arg2 interface{}) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateSpaceDeleteChange", reflect.TypeOf((*MockChangeFactory)(nil).CreateSpaceDeleteChange), arg0, arg1, arg2)
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ import "github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
||||||
|
|
||||||
type State struct {
|
type State struct {
|
||||||
DeletedIds map[string]struct{}
|
DeletedIds map[string]struct{}
|
||||||
DeleterId string
|
|
||||||
LastIteratedId string
|
LastIteratedId string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +17,6 @@ func NewStateFromSnapshot(snapshot *spacesyncproto.SpaceSettingsSnapshot, lastIt
|
||||||
for _, id := range snapshot.DeletedIds {
|
for _, id := range snapshot.DeletedIds {
|
||||||
st.DeletedIds[id] = struct{}{}
|
st.DeletedIds[id] = struct{}{}
|
||||||
}
|
}
|
||||||
st.DeleterId = snapshot.DeleterPeerId
|
|
||||||
st.LastIteratedId = lastIteratedId
|
st.LastIteratedId = lastIteratedId
|
||||||
return st
|
return st
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,8 +64,6 @@ func (s *stateBuilder) processChange(change *objecttree.Change, rootId string, s
|
||||||
switch {
|
switch {
|
||||||
case cnt.GetObjectDelete() != nil:
|
case cnt.GetObjectDelete() != nil:
|
||||||
state.DeletedIds[cnt.GetObjectDelete().GetId()] = struct{}{}
|
state.DeletedIds[cnt.GetObjectDelete().GetId()] = struct{}{}
|
||||||
case cnt.GetSpaceDelete() != nil:
|
|
||||||
state.DeleterId = cnt.GetSpaceDelete().GetDeleterPeerId()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return state
|
return state
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package settingsstate
|
package settingsstate
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/anyproto/any-sync/commonspace/object/accountdata"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
|
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree/mock_objecttree"
|
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree/mock_objecttree"
|
||||||
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
||||||
|
@ -22,6 +24,26 @@ func TestStateBuilder_ProcessChange(t *testing.T) {
|
||||||
require.Equal(t, map[string]struct{}{deletedId: struct{}{}}, newSt.DeletedIds)
|
require.Equal(t, map[string]struct{}{deletedId: struct{}{}}, newSt.DeletedIds)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("correct space deleted", func(t *testing.T) {
|
||||||
|
keys, _ := accountdata.NewRandom()
|
||||||
|
ch := &objecttree.Change{
|
||||||
|
Identity: keys.SignKey.GetPublic(),
|
||||||
|
}
|
||||||
|
ch.PreviousIds = []string{"someId"}
|
||||||
|
ch.Model = &spacesyncproto.SettingsData{
|
||||||
|
Content: []*spacesyncproto.SpaceSettingsContent{
|
||||||
|
{Value: &spacesyncproto.SpaceSettingsContent_SpaceDelete{
|
||||||
|
SpaceDelete: &spacesyncproto.SpaceDelete{DeleterPeerId: "peerId"},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
ch.Id = "someId"
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
defer ctrl.Finish()
|
||||||
|
newSt := sb.processChange(ch, rootId, NewState())
|
||||||
|
fmt.Println(newSt)
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("changeId is equal to startId, LastIteratedId is equal to startId", func(t *testing.T) {
|
t.Run("changeId is equal to startId, LastIteratedId is equal to startId", func(t *testing.T) {
|
||||||
ch := &objecttree.Change{}
|
ch := &objecttree.Change{}
|
||||||
ch.Model = &spacesyncproto.SettingsData{
|
ch.Model = &spacesyncproto.SettingsData{
|
||||||
|
@ -45,14 +67,12 @@ func TestStateBuilder_ProcessChange(t *testing.T) {
|
||||||
ch.PreviousIds = []string{"someId"}
|
ch.PreviousIds = []string{"someId"}
|
||||||
ch.Model = &spacesyncproto.SettingsData{
|
ch.Model = &spacesyncproto.SettingsData{
|
||||||
Snapshot: &spacesyncproto.SpaceSettingsSnapshot{
|
Snapshot: &spacesyncproto.SpaceSettingsSnapshot{
|
||||||
DeletedIds: []string{"id1", "id2"},
|
DeletedIds: []string{"id1", "id2"},
|
||||||
DeleterPeerId: "peerId",
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
ch.Id = "rootId"
|
ch.Id = "rootId"
|
||||||
newSt := sb.processChange(ch, rootId, NewState())
|
newSt := sb.processChange(ch, rootId, NewState())
|
||||||
require.Equal(t, map[string]struct{}{"id1": struct{}{}, "id2": struct{}{}}, newSt.DeletedIds)
|
require.Equal(t, map[string]struct{}{"id1": struct{}{}, "id2": struct{}{}}, newSt.DeletedIds)
|
||||||
require.Equal(t, "peerId", newSt.DeleterId)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("changeId is not equal to lastIteratedId or rootId", func(t *testing.T) {
|
t.Run("changeId is not equal to lastIteratedId or rootId", func(t *testing.T) {
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"github.com/anyproto/any-sync/commonspace/headsync"
|
"github.com/anyproto/any-sync/commonspace/headsync"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/acl/list"
|
"github.com/anyproto/any-sync/commonspace/object/acl/list"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/acl/syncacl"
|
"github.com/anyproto/any-sync/commonspace/object/acl/syncacl"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
|
|
||||||
"github.com/anyproto/any-sync/commonspace/objectsync"
|
"github.com/anyproto/any-sync/commonspace/objectsync"
|
||||||
"github.com/anyproto/any-sync/commonspace/objecttreebuilder"
|
"github.com/anyproto/any-sync/commonspace/objecttreebuilder"
|
||||||
"github.com/anyproto/any-sync/commonspace/peermanager"
|
"github.com/anyproto/any-sync/commonspace/peermanager"
|
||||||
|
@ -63,7 +62,7 @@ func NewSpaceId(id string, repKey uint64) string {
|
||||||
type Space interface {
|
type Space interface {
|
||||||
Id() string
|
Id() string
|
||||||
Init(ctx context.Context) error
|
Init(ctx context.Context) error
|
||||||
Acl() list.AclList
|
Acl() syncacl.SyncAcl
|
||||||
|
|
||||||
StoredIds() []string
|
StoredIds() []string
|
||||||
DebugAllHeads() []headsync.TreeHeads
|
DebugAllHeads() []headsync.TreeHeads
|
||||||
|
@ -74,9 +73,6 @@ type Space interface {
|
||||||
Storage() spacestorage.SpaceStorage
|
Storage() spacestorage.SpaceStorage
|
||||||
|
|
||||||
DeleteTree(ctx context.Context, id string) (err error)
|
DeleteTree(ctx context.Context, id string) (err error)
|
||||||
SpaceDeleteRawChange(ctx context.Context) (raw *treechangeproto.RawTreeChangeWithId, err error)
|
|
||||||
DeleteSpace(ctx context.Context, deleteChange *treechangeproto.RawTreeChangeWithId) (err error)
|
|
||||||
|
|
||||||
GetNodePeers(ctx context.Context) (peer []peer.Peer, err error)
|
GetNodePeers(ctx context.Context) (peer []peer.Peer, err error)
|
||||||
|
|
||||||
HandleMessage(ctx context.Context, msg objectsync.HandleMessage) (err error)
|
HandleMessage(ctx context.Context, msg objectsync.HandleMessage) (err error)
|
||||||
|
@ -137,14 +133,6 @@ func (s *space) DeleteTree(ctx context.Context, id string) (err error) {
|
||||||
return s.settings.DeleteTree(ctx, id)
|
return s.settings.DeleteTree(ctx, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *space) SpaceDeleteRawChange(ctx context.Context) (raw *treechangeproto.RawTreeChangeWithId, err error) {
|
|
||||||
return s.settings.SpaceDeleteRawChange(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *space) DeleteSpace(ctx context.Context, deleteChange *treechangeproto.RawTreeChangeWithId) (err error) {
|
|
||||||
return s.settings.DeleteSpace(ctx, deleteChange)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *space) HandleMessage(ctx context.Context, msg objectsync.HandleMessage) (err error) {
|
func (s *space) HandleMessage(ctx context.Context, msg objectsync.HandleMessage) (err error) {
|
||||||
return s.objectSync.HandleMessage(ctx, msg)
|
return s.objectSync.HandleMessage(ctx, msg)
|
||||||
}
|
}
|
||||||
|
@ -165,8 +153,8 @@ func (s *space) GetNodePeers(ctx context.Context) (peer []peer.Peer, err error)
|
||||||
return s.peerManager.GetNodePeers(ctx)
|
return s.peerManager.GetNodePeers(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *space) Acl() list.AclList {
|
func (s *space) Acl() syncacl.SyncAcl {
|
||||||
return s.aclList
|
return s.aclList.(syncacl.SyncAcl)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *space) Id() string {
|
func (s *space) Id() string {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package commonspace
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/anyproto/any-sync/commonspace/deletionmanager"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/anyproto/any-sync/accountservice"
|
"github.com/anyproto/any-sync/accountservice"
|
||||||
|
@ -179,6 +180,7 @@ func (s *spaceService) NewSpace(ctx context.Context, id string) (Space, error) {
|
||||||
Register(syncacl.New()).
|
Register(syncacl.New()).
|
||||||
Register(requestmanager.New()).
|
Register(requestmanager.New()).
|
||||||
Register(deletionstate.New()).
|
Register(deletionstate.New()).
|
||||||
|
Register(deletionmanager.New()).
|
||||||
Register(settings.New()).
|
Register(settings.New()).
|
||||||
Register(objectmanager.New(s.treeManager)).
|
Register(objectmanager.New(s.treeManager)).
|
||||||
Register(objecttreebuilder.New()).
|
Register(objecttreebuilder.New()).
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue