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 (
|
||||
"context"
|
|
@ -1,7 +1,8 @@
|
|||
package settings
|
||||
package deletionmanager
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/anyproto/any-sync/app/logger"
|
||||
"github.com/anyproto/any-sync/commonspace/deletionstate"
|
||||
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
|
||||
"github.com/anyproto/any-sync/commonspace/object/treemanager"
|
||||
|
@ -17,10 +18,11 @@ type deleter struct {
|
|||
st spacestorage.SpaceStorage
|
||||
state deletionstate.ObjectDeletionState
|
||||
getter treemanager.TreeManager
|
||||
log logger.CtxLogger
|
||||
}
|
||||
|
||||
func newDeleter(st spacestorage.SpaceStorage, state deletionstate.ObjectDeletionState, getter treemanager.TreeManager) Deleter {
|
||||
return &deleter{st, state, getter}
|
||||
func newDeleter(st spacestorage.SpaceStorage, state deletionstate.ObjectDeletionState, getter treemanager.TreeManager, log logger.CtxLogger) Deleter {
|
||||
return &deleter{st, state, getter, log}
|
||||
}
|
||||
|
||||
func (d *deleter) Delete() {
|
||||
|
@ -29,7 +31,7 @@ func (d *deleter) Delete() {
|
|||
spaceId = d.st.Id()
|
||||
)
|
||||
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)
|
||||
if !shouldDelete {
|
||||
if err != nil {
|
|
@ -1,4 +1,4 @@
|
|||
package settings
|
||||
package deletionmanager
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -16,7 +16,7 @@ func TestDeleter_Delete(t *testing.T) {
|
|||
st := mock_spacestorage.NewMockSpaceStorage(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) {
|
||||
id := "id"
|
||||
|
@ -50,7 +50,7 @@ func TestDeleter_Delete(t *testing.T) {
|
|||
|
||||
deleter.Delete()
|
||||
})
|
||||
//treeManager.EXPECT().DeleteTree(gomock.Any(), spaceId, id).Return(spacestorage.ErrTreeStorageAlreadyDeleted)
|
||||
|
||||
t.Run("deleter delete success", func(t *testing.T) {
|
||||
id := "id"
|
||||
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.
|
||||
// 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_settings
|
||||
// Package mock_deletionmanager is a generated GoMock package.
|
||||
package mock_deletionmanager
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
app "github.com/anyproto/any-sync/app"
|
||||
settingsstate "github.com/anyproto/any-sync/commonspace/settings/settingsstate"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
)
|
||||
|
@ -35,6 +36,62 @@ func (m *MockDeletionManager) EXPECT() *MockDeletionManagerMockRecorder {
|
|||
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.
|
||||
func (m *MockDeletionManager) UpdateState(arg0 context.Context, arg1 *settingsstate.State) error {
|
||||
m.ctrl.T.Helper()
|
||||
|
@ -120,3 +177,31 @@ func (mr *MockSpaceIdsProviderMockRecorder) AllIds() *gomock.Call {
|
|||
mr.mock.ctrl.T.Helper()
|
||||
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
|
||||
}
|
||||
rec = &AclRecord{
|
||||
PrevId: aclRecord.PrevId,
|
||||
Timestamp: aclRecord.Timestamp,
|
||||
Data: aclRecord.Data,
|
||||
Signature: rawRecord.Signature,
|
||||
Identity: pubKey,
|
||||
Model: aclData,
|
||||
PrevId: aclRecord.PrevId,
|
||||
Timestamp: aclRecord.Timestamp,
|
||||
AcceptorTimestamp: rawRecord.AcceptorTimestamp,
|
||||
Data: aclRecord.Data,
|
||||
Signature: rawRecord.Signature,
|
||||
Identity: pubKey,
|
||||
Model: aclData,
|
||||
}
|
||||
res, err := pubKey.Verify(rawRecord.Payload, rawRecord.Signature)
|
||||
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) {
|
||||
model := record.Model.(*aclrecordproto.AclData)
|
||||
for _, ch := range model.GetAclContent() {
|
||||
if err = st.applyChangeContent(ch, record.Id, record.Identity); err != nil {
|
||||
log.Info("error while applying changes: %v; ignore", zap.Error(err))
|
||||
if err = st.applyChangeContent(ch, record); err != nil {
|
||||
log.Info("error while applying changes; ignore", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
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 {
|
||||
case ch.GetPermissionChange() != nil:
|
||||
return st.applyPermissionChange(ch.GetPermissionChange(), recordId, authorIdentity)
|
||||
return st.applyPermissionChange(ch.GetPermissionChange(), record)
|
||||
case ch.GetInvite() != nil:
|
||||
return st.applyInvite(ch.GetInvite(), recordId, authorIdentity)
|
||||
return st.applyInvite(ch.GetInvite(), record)
|
||||
case ch.GetInviteRevoke() != nil:
|
||||
return st.applyInviteRevoke(ch.GetInviteRevoke(), recordId, authorIdentity)
|
||||
return st.applyInviteRevoke(ch.GetInviteRevoke(), record)
|
||||
case ch.GetRequestJoin() != nil:
|
||||
return st.applyRequestJoin(ch.GetRequestJoin(), recordId, authorIdentity)
|
||||
return st.applyRequestJoin(ch.GetRequestJoin(), record)
|
||||
case ch.GetRequestAccept() != nil:
|
||||
return st.applyRequestAccept(ch.GetRequestAccept(), recordId, authorIdentity)
|
||||
return st.applyRequestAccept(ch.GetRequestAccept(), record)
|
||||
case ch.GetRequestDecline() != nil:
|
||||
return st.applyRequestDecline(ch.GetRequestDecline(), recordId, authorIdentity)
|
||||
return st.applyRequestDecline(ch.GetRequestDecline(), record)
|
||||
case ch.GetAccountRemove() != nil:
|
||||
return st.applyAccountRemove(ch.GetAccountRemove(), recordId, authorIdentity)
|
||||
return st.applyAccountRemove(ch.GetAccountRemove(), record)
|
||||
case ch.GetReadKeyChange() != nil:
|
||||
return st.applyReadKeyChange(ch.GetReadKeyChange(), recordId, authorIdentity, true)
|
||||
return st.applyReadKeyChange(ch.GetReadKeyChange(), record, true)
|
||||
case ch.GetAccountRequestRemove() != nil:
|
||||
return st.applyRequestRemove(ch.GetAccountRequestRemove(), recordId, authorIdentity)
|
||||
return st.applyRequestRemove(ch.GetAccountRequestRemove(), record)
|
||||
default:
|
||||
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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = st.contentValidator.ValidatePermissionChange(ch, authorIdentity)
|
||||
err = st.contentValidator.ValidatePermissionChange(ch, record.Identity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -313,21 +313,21 @@ func (st *AclState) applyPermissionChange(ch *aclrecordproto.AclAccountPermissio
|
|||
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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = st.contentValidator.ValidateInvite(ch, authorIdentity)
|
||||
err = st.contentValidator.ValidateInvite(ch, record.Identity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
st.inviteKeys[recordId] = inviteKey
|
||||
st.inviteKeys[record.Id] = inviteKey
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st *AclState) applyInviteRevoke(ch *aclrecordproto.AclAccountInviteRevoke, recordId string, authorIdentity crypto.PubKey) error {
|
||||
err := st.contentValidator.ValidateInviteRevoke(ch, authorIdentity)
|
||||
func (st *AclState) applyInviteRevoke(ch *aclrecordproto.AclAccountInviteRevoke, record *AclRecord) error {
|
||||
err := st.contentValidator.ValidateInviteRevoke(ch, record.Identity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -335,22 +335,22 @@ func (st *AclState) applyInviteRevoke(ch *aclrecordproto.AclAccountInviteRevoke,
|
|||
return nil
|
||||
}
|
||||
|
||||
func (st *AclState) applyRequestJoin(ch *aclrecordproto.AclAccountRequestJoin, recordId string, authorIdentity crypto.PubKey) error {
|
||||
err := st.contentValidator.ValidateRequestJoin(ch, authorIdentity)
|
||||
func (st *AclState) applyRequestJoin(ch *aclrecordproto.AclAccountRequestJoin, record *AclRecord) error {
|
||||
err := st.contentValidator.ValidateRequestJoin(ch, record.Identity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
st.pendingRequests[mapKeyFromPubKey(authorIdentity)] = recordId
|
||||
st.requestRecords[recordId] = RequestRecord{
|
||||
RequestIdentity: authorIdentity,
|
||||
st.pendingRequests[mapKeyFromPubKey(record.Identity)] = record.Id
|
||||
st.requestRecords[record.Id] = RequestRecord{
|
||||
RequestIdentity: record.Identity,
|
||||
RequestMetadata: ch.Metadata,
|
||||
Type: RequestTypeJoin,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st *AclState) applyRequestAccept(ch *aclrecordproto.AclAccountRequestAccept, recordId string, authorIdentity crypto.PubKey) error {
|
||||
err := st.contentValidator.ValidateRequestAccept(ch, authorIdentity)
|
||||
func (st *AclState) applyRequestAccept(ch *aclrecordproto.AclAccountRequestAccept, record *AclRecord) error {
|
||||
err := st.contentValidator.ValidateRequestAccept(ch, record.Identity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -358,11 +358,11 @@ func (st *AclState) applyRequestAccept(ch *aclrecordproto.AclAccountRequestAccep
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
record, _ := st.requestRecords[ch.RequestRecordId]
|
||||
requestRecord, _ := st.requestRecords[ch.RequestRecordId]
|
||||
st.accountStates[mapKeyFromPubKey(acceptIdentity)] = AclAccountState{
|
||||
PubKey: acceptIdentity,
|
||||
Permissions: AclPermissions(ch.Permissions),
|
||||
RequestMetadata: record.RequestMetadata,
|
||||
RequestMetadata: requestRecord.RequestMetadata,
|
||||
KeyRecordId: st.CurrentReadKeyId(),
|
||||
}
|
||||
delete(st.pendingRequests, mapKeyFromPubKey(st.requestRecords[ch.RequestRecordId].RequestIdentity))
|
||||
|
@ -421,8 +421,8 @@ func (st *AclState) applyRequestAccept(ch *aclrecordproto.AclAccountRequestAccep
|
|||
return nil
|
||||
}
|
||||
|
||||
func (st *AclState) applyRequestDecline(ch *aclrecordproto.AclAccountRequestDecline, recordId string, authorIdentity crypto.PubKey) error {
|
||||
err := st.contentValidator.ValidateRequestDecline(ch, authorIdentity)
|
||||
func (st *AclState) applyRequestDecline(ch *aclrecordproto.AclAccountRequestDecline, record *AclRecord) error {
|
||||
err := st.contentValidator.ValidateRequestDecline(ch, record.Identity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -431,21 +431,21 @@ func (st *AclState) applyRequestDecline(ch *aclrecordproto.AclAccountRequestDecl
|
|||
return nil
|
||||
}
|
||||
|
||||
func (st *AclState) applyRequestRemove(ch *aclrecordproto.AclAccountRequestRemove, recordId string, authorIdentity crypto.PubKey) error {
|
||||
err := st.contentValidator.ValidateRequestRemove(ch, authorIdentity)
|
||||
func (st *AclState) applyRequestRemove(ch *aclrecordproto.AclAccountRequestRemove, record *AclRecord) error {
|
||||
err := st.contentValidator.ValidateRequestRemove(ch, record.Identity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
st.requestRecords[recordId] = RequestRecord{
|
||||
RequestIdentity: authorIdentity,
|
||||
st.requestRecords[record.Id] = RequestRecord{
|
||||
RequestIdentity: record.Identity,
|
||||
Type: RequestTypeRemove,
|
||||
}
|
||||
st.pendingRequests[mapKeyFromPubKey(authorIdentity)] = recordId
|
||||
st.pendingRequests[mapKeyFromPubKey(record.Identity)] = record.Id
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st *AclState) applyAccountRemove(ch *aclrecordproto.AclAccountRemove, recordId string, authorIdentity crypto.PubKey) error {
|
||||
err := st.contentValidator.ValidateAccountRemove(ch, authorIdentity)
|
||||
func (st *AclState) applyAccountRemove(ch *aclrecordproto.AclAccountRemove, record *AclRecord) error {
|
||||
err := st.contentValidator.ValidateAccountRemove(ch, record.Identity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -458,17 +458,17 @@ func (st *AclState) applyAccountRemove(ch *aclrecordproto.AclAccountRemove, reco
|
|||
delete(st.accountStates, 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 {
|
||||
err := st.contentValidator.ValidateReadKeyChange(ch, authorIdentity)
|
||||
err := st.contentValidator.ValidateReadKeyChange(ch, record.Identity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
st.readKeyChanges = append(st.readKeyChanges, recordId)
|
||||
st.readKeyChanges = append(st.readKeyChanges, record.Id)
|
||||
mkPubKey, err := st.keyStore.PubKeyFromProto(ch.MetadataPubKey)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -493,7 +493,7 @@ func (st *AclState) applyReadKeyChange(ch *aclrecordproto.AclReadKeyChange, reco
|
|||
}
|
||||
aclKeys.MetadataPrivKey = metadataKey
|
||||
}
|
||||
st.keys[recordId] = aclKeys
|
||||
st.keys[record.Id] = aclKeys
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -86,12 +86,11 @@ func (fx *aclFixture) inviteAccount(t *testing.T, perms AclPermissions) {
|
|||
fx.addRec(t, requestAcceptRec)
|
||||
|
||||
// checking acl state
|
||||
require.True(t, ownerState.Permissions(ownerState.pubKey).IsOwner())
|
||||
require.True(t, ownerState.Permissions(accountState.pubKey).CanWrite())
|
||||
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).CanWrite())
|
||||
for _, acl := range []*aclList{ownerAcl, accountAcl} {
|
||||
require.True(t, acl.AclState().Permissions(ownerAcl.AclState().pubKey).IsOwner())
|
||||
require.True(t, acl.AclState().Permissions(acl.AclState().pubKey).CanWrite())
|
||||
require.Equal(t, 0, len(acl.AclState().pendingRequests))
|
||||
}
|
||||
|
||||
_, err = ownerState.StateAtRecord(requestJoinRec.Id, accountState.pubKey)
|
||||
require.Equal(t, ErrNoSuchAccount, err)
|
||||
|
@ -295,14 +294,12 @@ func TestAclList_PermissionChange(t *testing.T) {
|
|||
fx.addRec(t, permissionChangeRec)
|
||||
|
||||
// checking acl state
|
||||
require.True(t, ownerState.Permissions(ownerState.pubKey).IsOwner())
|
||||
require.True(t, ownerState.Permissions(accountState.pubKey) == AclPermissions(aclrecordproto.AclUserPermissions_Writer))
|
||||
require.True(t, accountState.Permissions(ownerState.pubKey).IsOwner())
|
||||
require.True(t, accountState.Permissions(accountState.pubKey) == AclPermissions(aclrecordproto.AclUserPermissions_Writer))
|
||||
require.NotEmpty(t, ownerState.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))
|
||||
for _, acl := range []*aclList{fx.ownerAcl, fx.accountAcl} {
|
||||
require.True(t, acl.AclState().Permissions(ownerState.pubKey).IsOwner())
|
||||
require.True(t, acl.AclState().Permissions(accountState.pubKey).CanWrite())
|
||||
require.Equal(t, 0, len(acl.AclState().pendingRequests))
|
||||
require.NotEmpty(t, acl.AclState().keys[fx.ownerAcl.Id()])
|
||||
}
|
||||
}
|
||||
|
||||
func TestAclList_RequestRemove(t *testing.T) {
|
||||
|
@ -337,14 +334,13 @@ func TestAclList_RequestRemove(t *testing.T) {
|
|||
fx.addRec(t, removeRec)
|
||||
|
||||
// checking acl state
|
||||
require.True(t, ownerState.Permissions(ownerState.pubKey).IsOwner())
|
||||
require.True(t, ownerState.Permissions(accountState.pubKey).NoPermissions())
|
||||
for _, acl := range []*aclList{fx.ownerAcl, fx.accountAcl} {
|
||||
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.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.NotNil(t, accountState.keys[removeRec.Id].MetadataPubKey)
|
||||
require.Nil(t, accountState.keys[removeRec.Id].ReadKey)
|
||||
|
|
|
@ -6,13 +6,14 @@ import (
|
|||
)
|
||||
|
||||
type AclRecord struct {
|
||||
Id string
|
||||
PrevId string
|
||||
Timestamp int64
|
||||
Data []byte
|
||||
Identity crypto.PubKey
|
||||
Model interface{}
|
||||
Signature []byte
|
||||
Id string
|
||||
PrevId string
|
||||
Timestamp int64
|
||||
AcceptorTimestamp int64
|
||||
Data []byte
|
||||
Identity crypto.PubKey
|
||||
Model interface{}
|
||||
Signature []byte
|
||||
}
|
||||
|
||||
type RequestRecord struct {
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
package headupdater
|
||||
|
||||
import "github.com/anyproto/any-sync/commonspace/object/acl/list"
|
||||
|
||||
type HeadUpdater interface {
|
||||
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)
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (m *MockSyncAcl) SetHeadUpdater(arg0 headupdater.HeadUpdater) {
|
||||
m.ctrl.T.Helper()
|
||||
|
|
|
@ -33,6 +33,7 @@ type SyncAcl interface {
|
|||
syncobjectgetter.SyncObject
|
||||
SetHeadUpdater(updater headupdater.HeadUpdater)
|
||||
SyncWithPeer(ctx context.Context, peerId string) (err error)
|
||||
SetAclUpdater(updater headupdater.AclUpdater)
|
||||
}
|
||||
|
||||
func New() SyncAcl {
|
||||
|
@ -45,6 +46,13 @@ type syncAcl struct {
|
|||
syncHandler synchandler.SyncHandler
|
||||
headUpdater headupdater.HeadUpdater
|
||||
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) {
|
||||
|
@ -97,6 +105,9 @@ func (s *syncAcl) AddRawRecord(rawRec *consensusproto.RawRecordWithId) (err erro
|
|||
headUpdate := s.syncClient.CreateHeadUpdate(s, []*consensusproto.RawRecordWithId{rawRec})
|
||||
s.headUpdater.UpdateHeads(s.Id(), []string{rawRec.Id})
|
||||
s.syncClient.Broadcast(headUpdate)
|
||||
if s.aclUpdater != nil {
|
||||
s.aclUpdater.UpdateAcl(s)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -111,6 +122,9 @@ func (s *syncAcl) AddRawRecords(rawRecords []*consensusproto.RawRecordWithId) (e
|
|||
headUpdate := s.syncClient.CreateHeadUpdate(s, rawRecords)
|
||||
s.headUpdater.UpdateHeads(s.Id(), []string{rawRecords[len(rawRecords)-1].Id})
|
||||
s.syncClient.Broadcast(headUpdate)
|
||||
if s.aclUpdater != nil {
|
||||
s.aclUpdater.UpdateAcl(s)
|
||||
}
|
||||
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 (
|
||||
"context"
|
||||
"github.com/anyproto/any-sync/commonspace/deletionmanager"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/anyproto/any-sync/accountservice"
|
||||
"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/synctree"
|
||||
"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/spacestate"
|
||||
"github.com/anyproto/any-sync/commonspace/spacestorage"
|
||||
|
@ -24,8 +21,6 @@ const CName = "common.commonspace.settings"
|
|||
|
||||
type Settings interface {
|
||||
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
|
||||
app.ComponentRunnable
|
||||
}
|
||||
|
@ -36,11 +31,8 @@ func New() Settings {
|
|||
|
||||
type settings struct {
|
||||
account accountservice.Service
|
||||
treeManager treemanager.TreeManager
|
||||
storage spacestorage.SpaceStorage
|
||||
configuration nodeconf.NodeConf
|
||||
deletionState deletionstate.ObjectDeletionState
|
||||
headsync headsync.HeadSync
|
||||
treeBuilder objecttreebuilder.TreeBuilderComponent
|
||||
spaceIsDeleted *atomic.Bool
|
||||
|
||||
|
@ -49,12 +41,8 @@ type settings struct {
|
|||
|
||||
func (s *settings) Init(a *app.App) (err error) {
|
||||
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.deletionState = a.MustComponent(deletionstate.CName).(deletionstate.ObjectDeletionState)
|
||||
s.treeBuilder = a.MustComponent(objecttreebuilder.CName).(objecttreebuilder.TreeBuilderComponent)
|
||||
|
||||
sharedState := a.MustComponent(spacestate.CName).(*spacestate.SpaceState)
|
||||
s.storage = a.MustComponent(spacestorage.CName).(spacestorage.SpaceStorage)
|
||||
s.spaceIsDeleted = sharedState.SpaceIsDeleted
|
||||
|
@ -74,12 +62,9 @@ func (s *settings) Init(a *app.App) (err error) {
|
|||
return
|
||||
},
|
||||
Account: s.account,
|
||||
TreeManager: s.treeManager,
|
||||
Store: s.storage,
|
||||
Configuration: s.configuration,
|
||||
DeletionState: s.deletionState,
|
||||
Provider: s.headsync,
|
||||
OnSpaceDelete: s.onSpaceDelete,
|
||||
DelManager: a.MustComponent(deletionmanager.CName).(deletionmanager.DeletionManager),
|
||||
}
|
||||
s.settingsObject = NewSettingsObject(deps, sharedState.SpaceId)
|
||||
return nil
|
||||
|
@ -101,22 +86,6 @@ func (s *settings) DeleteTree(ctx context.Context, id string) (err error) {
|
|||
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 {
|
||||
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
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"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/accountservice"
|
||||
|
@ -21,7 +20,6 @@ import (
|
|||
"github.com/anyproto/any-sync/nodeconf"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
var log = logger.NewNamed("common.commonspace.settings")
|
||||
|
@ -30,8 +28,6 @@ type SettingsObject interface {
|
|||
synctree.SyncTree
|
||||
Init(ctx context.Context) (err error)
|
||||
DeleteObject(id string) (err error)
|
||||
DeleteSpace(ctx context.Context, raw *treechangeproto.RawTreeChangeWithId) (err error)
|
||||
SpaceDeleteRawChange() (raw *treechangeproto.RawTreeChangeWithId, err error)
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -60,56 +56,30 @@ type Deps struct {
|
|||
TreeManager treemanager.TreeManager
|
||||
Store spacestorage.SpaceStorage
|
||||
Configuration nodeconf.NodeConf
|
||||
DeletionState deletionstate.ObjectDeletionState
|
||||
Provider SpaceIdsProvider
|
||||
OnSpaceDelete func()
|
||||
DelManager deletionmanager.DeletionManager
|
||||
// testing dependencies
|
||||
builder settingsstate.StateBuilder
|
||||
del Deleter
|
||||
delManager DeletionManager
|
||||
changeFactory settingsstate.ChangeFactory
|
||||
}
|
||||
|
||||
type settingsObject struct {
|
||||
synctree.SyncTree
|
||||
account accountservice.Service
|
||||
spaceId string
|
||||
treeManager treemanager.TreeManager
|
||||
store spacestorage.SpaceStorage
|
||||
builder settingsstate.StateBuilder
|
||||
buildFunc BuildTreeFunc
|
||||
loop *deleteLoop
|
||||
account accountservice.Service
|
||||
spaceId string
|
||||
store spacestorage.SpaceStorage
|
||||
builder settingsstate.StateBuilder
|
||||
buildFunc BuildTreeFunc
|
||||
|
||||
state *settingsstate.State
|
||||
deletionState deletionstate.ObjectDeletionState
|
||||
deletionManager DeletionManager
|
||||
deletionManager deletionmanager.DeletionManager
|
||||
changeFactory settingsstate.ChangeFactory
|
||||
}
|
||||
|
||||
func NewSettingsObject(deps Deps, spaceId string) (obj SettingsObject) {
|
||||
var (
|
||||
deleter Deleter
|
||||
deletionManager DeletionManager
|
||||
builder settingsstate.StateBuilder
|
||||
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 {
|
||||
builder = settingsstate.NewStateBuilder()
|
||||
} else {
|
||||
|
@ -121,23 +91,13 @@ func NewSettingsObject(deps Deps, spaceId string) (obj SettingsObject) {
|
|||
changeFactory = deps.changeFactory
|
||||
}
|
||||
|
||||
loop := newDeleteLoop(func() {
|
||||
deleter.Delete()
|
||||
})
|
||||
deps.DeletionState.AddObserver(func(ids []string) {
|
||||
loop.notify()
|
||||
})
|
||||
|
||||
s := &settingsObject{
|
||||
loop: loop,
|
||||
spaceId: spaceId,
|
||||
account: deps.Account,
|
||||
deletionState: deps.DeletionState,
|
||||
treeManager: deps.TreeManager,
|
||||
store: deps.Store,
|
||||
buildFunc: deps.BuildFunc,
|
||||
builder: builder,
|
||||
deletionManager: deletionManager,
|
||||
deletionManager: deps.DelManager,
|
||||
changeFactory: changeFactory,
|
||||
}
|
||||
obj = s
|
||||
|
@ -151,7 +111,6 @@ func (s *settingsObject) updateIds(tr objecttree.ObjectTree) {
|
|||
log.Error("failed to build state", zap.Error(err))
|
||||
return
|
||||
}
|
||||
log.Debug("updating object state", zap.String("deleted by", s.state.DeleterId))
|
||||
if err = s.deletionManager.UpdateState(context.Background(), s.state); err != nil {
|
||||
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 {
|
||||
return
|
||||
}
|
||||
s.loop.Run()
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -207,48 +165,9 @@ func (s *settingsObject) checkHistoryState(ctx context.Context) (err error) {
|
|||
}
|
||||
|
||||
func (s *settingsObject) Close() error {
|
||||
s.loop.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) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
|
|
@ -3,16 +3,14 @@ package settings
|
|||
import (
|
||||
"context"
|
||||
"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/tree/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/mock_synctree"
|
||||
"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/settings/mock_settings"
|
||||
"github.com/anyproto/any-sync/commonspace/settings/settingsstate"
|
||||
"github.com/anyproto/any-sync/commonspace/settings/settingsstate/mock_settingsstate"
|
||||
"github.com/anyproto/any-sync/commonspace/spacestorage/mock_spacestorage"
|
||||
|
@ -50,12 +48,10 @@ type settingsFixture struct {
|
|||
treeManager *mock_treemanager.MockTreeManager
|
||||
spaceStorage *mock_spacestorage.MockSpaceStorage
|
||||
stateBuilder *mock_settingsstate.MockStateBuilder
|
||||
deletionManager *mock_settings.MockDeletionManager
|
||||
deletionManager *mock_deletionmanager.MockDeletionManager
|
||||
changeFactory *mock_settingsstate.MockChangeFactory
|
||||
deleter *mock_settings.MockDeleter
|
||||
syncTree *mock_synctree.MockSyncTree
|
||||
historyTree *mock_objecttree.MockObjectTree
|
||||
delState *mock_deletionstate.MockObjectDeletionState
|
||||
account *mock_accountservice.MockService
|
||||
}
|
||||
|
||||
|
@ -67,15 +63,11 @@ func newSettingsFixture(t *testing.T) *settingsFixture {
|
|||
acc := mock_accountservice.NewMockService(ctrl)
|
||||
treeManager := mock_treemanager.NewMockTreeManager(ctrl)
|
||||
st := mock_spacestorage.NewMockSpaceStorage(ctrl)
|
||||
delState := mock_deletionstate.NewMockObjectDeletionState(ctrl)
|
||||
delManager := mock_settings.NewMockDeletionManager(ctrl)
|
||||
delManager := mock_deletionmanager.NewMockDeletionManager(ctrl)
|
||||
stateBuilder := mock_settingsstate.NewMockStateBuilder(ctrl)
|
||||
changeFactory := mock_settingsstate.NewMockChangeFactory(ctrl)
|
||||
syncTree := mock_synctree.NewMockSyncTree(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) {
|
||||
require.Equal(t, objectId, id)
|
||||
|
@ -90,11 +82,9 @@ func newSettingsFixture(t *testing.T) *settingsFixture {
|
|||
Account: acc,
|
||||
TreeManager: treeManager,
|
||||
Store: st,
|
||||
DeletionState: delState,
|
||||
delManager: delManager,
|
||||
DelManager: delManager,
|
||||
changeFactory: changeFactory,
|
||||
builder: stateBuilder,
|
||||
del: del,
|
||||
}
|
||||
doc := NewSettingsObject(deps, spaceId).(*settingsObject)
|
||||
return &settingsFixture{
|
||||
|
@ -107,17 +97,14 @@ func newSettingsFixture(t *testing.T) *settingsFixture {
|
|||
stateBuilder: stateBuilder,
|
||||
changeFactory: changeFactory,
|
||||
deletionManager: delManager,
|
||||
deleter: del,
|
||||
syncTree: syncTree,
|
||||
account: acc,
|
||||
delState: delState,
|
||||
historyTree: historyTree,
|
||||
}
|
||||
}
|
||||
|
||||
func (fx *settingsFixture) init(t *testing.T) {
|
||||
fx.spaceStorage.EXPECT().SpaceSettingsId().Return(fx.docId)
|
||||
fx.deleter.EXPECT().Delete()
|
||||
fx.stateBuilder.EXPECT().Build(fx.historyTree, nil).Return(&settingsstate.State{}, nil)
|
||||
fx.doc.state = &settingsstate.State{}
|
||||
|
||||
|
@ -235,64 +222,3 @@ func TestSettingsObject_Update(t *testing.T) {
|
|||
|
||||
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 {
|
||||
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 {
|
||||
|
@ -26,44 +25,23 @@ func (c *changeFactory) CreateObjectDeleteChange(id string, state *State, isSnap
|
|||
},
|
||||
}
|
||||
if isSnapshot {
|
||||
change.Snapshot = c.makeSnapshot(state, id, "")
|
||||
change.Snapshot = c.makeSnapshot(state, id)
|
||||
}
|
||||
res, err = change.Marshal()
|
||||
return
|
||||
}
|
||||
|
||||
func (c *changeFactory) CreateSpaceDeleteChange(peerId string, state *State, isSnapshot bool) (res []byte, err error) {
|
||||
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 {
|
||||
func (c *changeFactory) makeSnapshot(state *State, objectId string) *spacesyncproto.SpaceSettingsSnapshot {
|
||||
var (
|
||||
deletedIds = make([]string, 0, len(state.DeletedIds)+1)
|
||||
deleterId = state.DeleterId
|
||||
)
|
||||
if objectId != "" {
|
||||
deletedIds = append(deletedIds, objectId)
|
||||
}
|
||||
if deleterPeer != "" {
|
||||
deleterId = deleterPeer
|
||||
}
|
||||
for id := range state.DeletedIds {
|
||||
deletedIds = append(deletedIds, id)
|
||||
}
|
||||
return &spacesyncproto.SpaceSettingsSnapshot{
|
||||
DeletedIds: deletedIds,
|
||||
DeleterPeerId: deleterId,
|
||||
DeletedIds: deletedIds,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ func TestChangeFactory_CreateObjectDeleteChange(t *testing.T) {
|
|||
factory := NewChangeFactory()
|
||||
state := &State{
|
||||
DeletedIds: map[string]struct{}{"1": {}, "2": {}},
|
||||
DeleterId: "del",
|
||||
}
|
||||
marshalled, err := factory.CreateObjectDeleteChange("3", state, false)
|
||||
require.NoError(t, err)
|
||||
|
@ -29,34 +28,7 @@ func TestChangeFactory_CreateObjectDeleteChange(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
slices.Sort(data.Snapshot.DeletedIds)
|
||||
require.Equal(t, &spacesyncproto.SpaceSettingsSnapshot{
|
||||
DeletedIds: []string{"1", "2", "3"},
|
||||
DeleterPeerId: "del",
|
||||
DeletedIds: []string{"1", "2", "3"},
|
||||
}, data.Snapshot)
|
||||
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()
|
||||
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 {
|
||||
DeletedIds map[string]struct{}
|
||||
DeleterId string
|
||||
LastIteratedId string
|
||||
}
|
||||
|
||||
|
@ -18,7 +17,6 @@ func NewStateFromSnapshot(snapshot *spacesyncproto.SpaceSettingsSnapshot, lastIt
|
|||
for _, id := range snapshot.DeletedIds {
|
||||
st.DeletedIds[id] = struct{}{}
|
||||
}
|
||||
st.DeleterId = snapshot.DeleterPeerId
|
||||
st.LastIteratedId = lastIteratedId
|
||||
return st
|
||||
}
|
||||
|
|
|
@ -64,8 +64,6 @@ func (s *stateBuilder) processChange(change *objecttree.Change, rootId string, s
|
|||
switch {
|
||||
case cnt.GetObjectDelete() != nil:
|
||||
state.DeletedIds[cnt.GetObjectDelete().GetId()] = struct{}{}
|
||||
case cnt.GetSpaceDelete() != nil:
|
||||
state.DeleterId = cnt.GetSpaceDelete().GetDeleterPeerId()
|
||||
}
|
||||
}
|
||||
return state
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package settingsstate
|
||||
|
||||
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/mock_objecttree"
|
||||
"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)
|
||||
})
|
||||
|
||||
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) {
|
||||
ch := &objecttree.Change{}
|
||||
ch.Model = &spacesyncproto.SettingsData{
|
||||
|
@ -45,14 +67,12 @@ func TestStateBuilder_ProcessChange(t *testing.T) {
|
|||
ch.PreviousIds = []string{"someId"}
|
||||
ch.Model = &spacesyncproto.SettingsData{
|
||||
Snapshot: &spacesyncproto.SpaceSettingsSnapshot{
|
||||
DeletedIds: []string{"id1", "id2"},
|
||||
DeleterPeerId: "peerId",
|
||||
DeletedIds: []string{"id1", "id2"},
|
||||
},
|
||||
}
|
||||
ch.Id = "rootId"
|
||||
newSt := sb.processChange(ch, rootId, NewState())
|
||||
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) {
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"github.com/anyproto/any-sync/commonspace/headsync"
|
||||
"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/tree/treechangeproto"
|
||||
"github.com/anyproto/any-sync/commonspace/objectsync"
|
||||
"github.com/anyproto/any-sync/commonspace/objecttreebuilder"
|
||||
"github.com/anyproto/any-sync/commonspace/peermanager"
|
||||
|
@ -63,7 +62,7 @@ func NewSpaceId(id string, repKey uint64) string {
|
|||
type Space interface {
|
||||
Id() string
|
||||
Init(ctx context.Context) error
|
||||
Acl() list.AclList
|
||||
Acl() syncacl.SyncAcl
|
||||
|
||||
StoredIds() []string
|
||||
DebugAllHeads() []headsync.TreeHeads
|
||||
|
@ -74,9 +73,6 @@ type Space interface {
|
|||
Storage() spacestorage.SpaceStorage
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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) {
|
||||
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)
|
||||
}
|
||||
|
||||
func (s *space) Acl() list.AclList {
|
||||
return s.aclList
|
||||
func (s *space) Acl() syncacl.SyncAcl {
|
||||
return s.aclList.(syncacl.SyncAcl)
|
||||
}
|
||||
|
||||
func (s *space) Id() string {
|
||||
|
|
|
@ -2,6 +2,7 @@ package commonspace
|
|||
|
||||
import (
|
||||
"context"
|
||||
"github.com/anyproto/any-sync/commonspace/deletionmanager"
|
||||
"sync/atomic"
|
||||
|
||||
"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(requestmanager.New()).
|
||||
Register(deletionstate.New()).
|
||||
Register(deletionmanager.New()).
|
||||
Register(settings.New()).
|
||||
Register(objectmanager.New(s.treeManager)).
|
||||
Register(objecttreebuilder.New()).
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue