merge and fix test
This commit is contained in:
commit
bc9ffc1a79
7
Makefile
7
Makefile
@ -31,12 +31,15 @@ proto:
|
||||
$(GOGO_START) protoc --gogofaster_out=$(PKGMAP):. --go-drpc_out=protolib=github.com/gogo/protobuf:. common/commonspace/spacesyncproto/protos/*.proto
|
||||
$(GOGO_START) protoc --gogofaster_out=:. --go-drpc_out=protolib=github.com/gogo/protobuf:. consensus/consensusproto/protos/*.proto
|
||||
|
||||
|
||||
|
||||
build:
|
||||
@$(eval FLAGS := $$(shell govvv -flags -pkg github.com/anytypeio/go-anytype-infrastructure-experiments/app))
|
||||
go build -v -o bin/anytype-node -ldflags "$(FLAGS)" cmd/node/node.go
|
||||
|
||||
test-deps:
|
||||
@echo 'Generating test mocks...'
|
||||
@go install github.com/golang/mock/mockgen
|
||||
@go generate ./...
|
||||
|
||||
build-consensus:
|
||||
@$(eval FLAGS := $$(shell govvv -flags -pkg github.com/anytypeio/go-anytype-infrastructure-experiments/app))
|
||||
go build -v -o bin/consensus-node -ldflags "$(FLAGS)" github.com/anytypeio/go-anytype-infrastructure-experiments/cmd/consensusnode
|
||||
|
||||
108
common/commonspace/cache/mock_cache/mock_cache.go
vendored
Normal file
108
common/commonspace/cache/mock_cache/mock_cache.go
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache (interfaces: TreeCache)
|
||||
|
||||
// Package mock_cache is a generated GoMock package.
|
||||
package mock_cache
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
app "github.com/anytypeio/go-anytype-infrastructure-experiments/app"
|
||||
cache "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockTreeCache is a mock of TreeCache interface.
|
||||
type MockTreeCache struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockTreeCacheMockRecorder
|
||||
}
|
||||
|
||||
// MockTreeCacheMockRecorder is the mock recorder for MockTreeCache.
|
||||
type MockTreeCacheMockRecorder struct {
|
||||
mock *MockTreeCache
|
||||
}
|
||||
|
||||
// NewMockTreeCache creates a new mock instance.
|
||||
func NewMockTreeCache(ctrl *gomock.Controller) *MockTreeCache {
|
||||
mock := &MockTreeCache{ctrl: ctrl}
|
||||
mock.recorder = &MockTreeCacheMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockTreeCache) EXPECT() *MockTreeCacheMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Close mocks base method.
|
||||
func (m *MockTreeCache) 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 *MockTreeCacheMockRecorder) Close(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockTreeCache)(nil).Close), arg0)
|
||||
}
|
||||
|
||||
// GetTree mocks base method.
|
||||
func (m *MockTreeCache) GetTree(arg0 context.Context, arg1, arg2 string) (cache.TreeResult, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetTree", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(cache.TreeResult)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetTree indicates an expected call of GetTree.
|
||||
func (mr *MockTreeCacheMockRecorder) GetTree(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTree", reflect.TypeOf((*MockTreeCache)(nil).GetTree), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// Init mocks base method.
|
||||
func (m *MockTreeCache) 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 *MockTreeCacheMockRecorder) Init(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Init", reflect.TypeOf((*MockTreeCache)(nil).Init), arg0)
|
||||
}
|
||||
|
||||
// Name mocks base method.
|
||||
func (m *MockTreeCache) 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 *MockTreeCacheMockRecorder) Name() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockTreeCache)(nil).Name))
|
||||
}
|
||||
|
||||
// Run mocks base method.
|
||||
func (m *MockTreeCache) 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 *MockTreeCacheMockRecorder) Run(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Run", reflect.TypeOf((*MockTreeCache)(nil).Run), arg0)
|
||||
}
|
||||
1
common/commonspace/cache/treecache.go
vendored
1
common/commonspace/cache/treecache.go
vendored
@ -1,3 +1,4 @@
|
||||
//go:generate mockgen -destination mock_cache/mock_cache.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache TreeCache
|
||||
package cache
|
||||
|
||||
import (
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
//go:generate mockgen -destination mock_diffservice/mock_diffservice.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice DiffSyncer,PeriodicSync
|
||||
package diffservice
|
||||
|
||||
import (
|
||||
@ -6,13 +7,10 @@ import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/remotediff"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/rpc/rpcerr"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff"
|
||||
"go.uber.org/zap"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type DiffService interface {
|
||||
@ -26,11 +24,9 @@ type DiffService interface {
|
||||
|
||||
type diffService struct {
|
||||
spaceId string
|
||||
periodicSync *periodicSync
|
||||
periodicSync PeriodicSync
|
||||
storage storage.SpaceStorage
|
||||
nconf nodeconf.Configuration
|
||||
diff ldiff.Diff
|
||||
cache cache.TreeCache
|
||||
log *zap.Logger
|
||||
|
||||
syncPeriod int
|
||||
@ -40,23 +36,29 @@ func NewDiffService(
|
||||
spaceId string,
|
||||
syncPeriod int,
|
||||
storage storage.SpaceStorage,
|
||||
nconf nodeconf.Configuration,
|
||||
confConnector nodeconf.ConfConnector,
|
||||
cache cache.TreeCache,
|
||||
log *zap.Logger) DiffService {
|
||||
|
||||
diff := ldiff.New(16, 16)
|
||||
l := log.With(zap.String("spaceId", spaceId))
|
||||
factory := spacesyncproto.ClientFactoryFunc(spacesyncproto.NewDRPCSpaceClient)
|
||||
syncer := newDiffSyncer(spaceId, diff, confConnector, cache, storage, factory, l)
|
||||
periodicSync := newPeriodicSync(syncPeriod, syncer, l)
|
||||
|
||||
return &diffService{
|
||||
spaceId: spaceId,
|
||||
storage: storage,
|
||||
nconf: nconf,
|
||||
cache: cache,
|
||||
log: log,
|
||||
syncPeriod: syncPeriod,
|
||||
spaceId: spaceId,
|
||||
storage: storage,
|
||||
periodicSync: periodicSync,
|
||||
diff: diff,
|
||||
log: log,
|
||||
syncPeriod: syncPeriod,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *diffService) Init(objectIds []string) {
|
||||
d.periodicSync = newPeriodicSync(d.syncPeriod, d.sync, d.log.With(zap.String("spaceId", d.spaceId)))
|
||||
d.diff = ldiff.New(16, 16)
|
||||
d.fillDiff(objectIds)
|
||||
d.periodicSync.Run()
|
||||
}
|
||||
|
||||
func (d *diffService) HandleRangeRequest(ctx context.Context, req *spacesyncproto.HeadSyncRequest) (resp *spacesyncproto.HeadSyncResponse, err error) {
|
||||
@ -80,49 +82,6 @@ func (d *diffService) Close() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *diffService) sync(ctx context.Context) error {
|
||||
st := time.Now()
|
||||
// diffing with responsible peers according to configuration
|
||||
peers, err := d.nconf.ResponsiblePeers(ctx, d.spaceId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, p := range peers {
|
||||
if err := d.syncWithPeer(ctx, p); err != nil {
|
||||
d.log.Error("can't sync with peer", zap.String("peer", p.Id()), zap.Error(err))
|
||||
}
|
||||
}
|
||||
d.log.Info("synced", zap.String("spaceId", d.spaceId), zap.Duration("dur", time.Since(st)))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *diffService) syncWithPeer(ctx context.Context, p peer.Peer) (err error) {
|
||||
cl := spacesyncproto.NewDRPCSpaceClient(p)
|
||||
rdiff := remotediff.NewRemoteDiff(d.spaceId, cl)
|
||||
newIds, changedIds, removedIds, err := d.diff.Diff(ctx, rdiff)
|
||||
err = rpcerr.Unwrap(err)
|
||||
if err != nil && err != spacesyncproto.ErrSpaceMissing {
|
||||
return err
|
||||
}
|
||||
if err == spacesyncproto.ErrSpaceMissing {
|
||||
return d.sendPushSpaceRequest(ctx, cl)
|
||||
}
|
||||
|
||||
d.pingTreesInCache(ctx, newIds)
|
||||
d.pingTreesInCache(ctx, changedIds)
|
||||
|
||||
d.log.Info("sync done:", zap.Int("newIds", len(newIds)),
|
||||
zap.Int("changedIds", len(changedIds)),
|
||||
zap.Int("removedIds", len(removedIds)))
|
||||
return
|
||||
}
|
||||
|
||||
func (d *diffService) pingTreesInCache(ctx context.Context, trees []string) {
|
||||
for _, tId := range trees {
|
||||
_, _ = d.cache.GetTree(ctx, d.spaceId, tId)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *diffService) fillDiff(objectIds []string) {
|
||||
var els = make([]ldiff.Element, 0, len(objectIds))
|
||||
for _, id := range objectIds {
|
||||
@ -142,30 +101,6 @@ func (d *diffService) fillDiff(objectIds []string) {
|
||||
d.diff.Set(els...)
|
||||
}
|
||||
|
||||
func (d *diffService) sendPushSpaceRequest(ctx context.Context, cl spacesyncproto.DRPCSpaceClient) (err error) {
|
||||
aclStorage, err := d.storage.ACLStorage()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
root, err := aclStorage.Root()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
header, err := d.storage.SpaceHeader()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = cl.PushSpace(ctx, &spacesyncproto.PushSpaceRequest{
|
||||
SpaceId: d.spaceId,
|
||||
SpaceHeader: header,
|
||||
AclRoot: root,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func concatStrings(strs []string) string {
|
||||
var (
|
||||
b strings.Builder
|
||||
|
||||
59
common/commonspace/diffservice/diffservice_test.go
Normal file
59
common/commonspace/diffservice/diffservice_test.go
Normal file
@ -0,0 +1,59 @@
|
||||
package diffservice
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice/mock_diffservice"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage/mock_storage"
|
||||
mock_storage2 "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage/mock_storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff/mock_ldiff"
|
||||
"github.com/golang/mock/gomock"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDiffService(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
spaceId := "spaceId"
|
||||
l := logger.NewNamed("sync")
|
||||
pSyncMock := mock_diffservice.NewMockPeriodicSync(ctrl)
|
||||
storageMock := mock_storage.NewMockSpaceStorage(ctrl)
|
||||
treeStorageMock := mock_storage2.NewMockTreeStorage(ctrl)
|
||||
diffMock := mock_ldiff.NewMockDiff(ctrl)
|
||||
syncPeriod := 1
|
||||
initId := "initId"
|
||||
|
||||
service := &diffService{
|
||||
spaceId: spaceId,
|
||||
storage: storageMock,
|
||||
periodicSync: pSyncMock,
|
||||
diff: diffMock,
|
||||
log: l,
|
||||
syncPeriod: syncPeriod,
|
||||
}
|
||||
|
||||
t.Run("init", func(t *testing.T) {
|
||||
storageMock.EXPECT().TreeStorage(initId).Return(treeStorageMock, nil)
|
||||
treeStorageMock.EXPECT().Heads().Return([]string{"h1", "h2"}, nil)
|
||||
diffMock.EXPECT().Set(ldiff.Element{
|
||||
Id: initId,
|
||||
Head: "h1h2",
|
||||
})
|
||||
pSyncMock.EXPECT().Run()
|
||||
service.Init([]string{initId})
|
||||
})
|
||||
|
||||
t.Run("update heads", func(t *testing.T) {
|
||||
diffMock.EXPECT().Set(ldiff.Element{
|
||||
Id: initId,
|
||||
Head: "h1h2",
|
||||
})
|
||||
service.UpdateHeads(initId, []string{"h1", "h2"})
|
||||
})
|
||||
|
||||
t.Run("close", func(t *testing.T) {
|
||||
pSyncMock.EXPECT().Close()
|
||||
service.Close()
|
||||
})
|
||||
}
|
||||
115
common/commonspace/diffservice/diffsyncer.go
Normal file
115
common/commonspace/diffservice/diffsyncer.go
Normal file
@ -0,0 +1,115 @@
|
||||
package diffservice
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/remotediff"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/rpc/rpcerr"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff"
|
||||
"go.uber.org/zap"
|
||||
"time"
|
||||
)
|
||||
|
||||
type DiffSyncer interface {
|
||||
Sync(ctx context.Context) error
|
||||
}
|
||||
|
||||
func newDiffSyncer(
|
||||
spaceId string,
|
||||
diff ldiff.Diff,
|
||||
confConnector nodeconf.ConfConnector,
|
||||
cache cache.TreeCache,
|
||||
storage storage.SpaceStorage,
|
||||
clientFactory spacesyncproto.ClientFactory,
|
||||
log *zap.Logger) DiffSyncer {
|
||||
return &diffSyncer{
|
||||
diff: diff,
|
||||
spaceId: spaceId,
|
||||
cache: cache,
|
||||
storage: storage,
|
||||
confConnector: confConnector,
|
||||
clientFactory: clientFactory,
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
type diffSyncer struct {
|
||||
spaceId string
|
||||
diff ldiff.Diff
|
||||
confConnector nodeconf.ConfConnector
|
||||
cache cache.TreeCache
|
||||
storage storage.SpaceStorage
|
||||
clientFactory spacesyncproto.ClientFactory
|
||||
log *zap.Logger
|
||||
}
|
||||
|
||||
func (d *diffSyncer) Sync(ctx context.Context) error {
|
||||
st := time.Now()
|
||||
// diffing with responsible peers according to configuration
|
||||
peers, err := d.confConnector.GetResponsiblePeers(ctx, d.spaceId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, p := range peers {
|
||||
if err := d.syncWithPeer(ctx, p); err != nil {
|
||||
d.log.Error("can't sync with peer", zap.String("peer", p.Id()), zap.Error(err))
|
||||
}
|
||||
}
|
||||
d.log.Info("synced", zap.String("spaceId", d.spaceId), zap.Duration("dur", time.Since(st)))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *diffSyncer) syncWithPeer(ctx context.Context, p peer.Peer) (err error) {
|
||||
cl := d.clientFactory.Client(p)
|
||||
rdiff := remotediff.NewRemoteDiff(d.spaceId, cl)
|
||||
newIds, changedIds, removedIds, err := d.diff.Diff(ctx, rdiff)
|
||||
err = rpcerr.Unwrap(err)
|
||||
if err != nil && err != spacesyncproto.ErrSpaceMissing {
|
||||
return err
|
||||
}
|
||||
if err == spacesyncproto.ErrSpaceMissing {
|
||||
return d.sendPushSpaceRequest(ctx, cl)
|
||||
}
|
||||
|
||||
d.pingTreesInCache(ctx, newIds)
|
||||
d.pingTreesInCache(ctx, changedIds)
|
||||
|
||||
d.log.Info("sync done:", zap.Int("newIds", len(newIds)),
|
||||
zap.Int("changedIds", len(changedIds)),
|
||||
zap.Int("removedIds", len(removedIds)))
|
||||
return
|
||||
}
|
||||
|
||||
func (d *diffSyncer) pingTreesInCache(ctx context.Context, trees []string) {
|
||||
for _, tId := range trees {
|
||||
_, _ = d.cache.GetTree(ctx, d.spaceId, tId)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *diffSyncer) sendPushSpaceRequest(ctx context.Context, cl spacesyncproto.DRPCSpaceClient) (err error) {
|
||||
aclStorage, err := d.storage.ACLStorage()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
root, err := aclStorage.Root()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
header, err := d.storage.SpaceHeader()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = cl.PushSpace(ctx, &spacesyncproto.PushSpaceRequest{
|
||||
SpaceId: d.spaceId,
|
||||
SpaceHeader: header,
|
||||
AclRoot: root,
|
||||
})
|
||||
return
|
||||
}
|
||||
162
common/commonspace/diffservice/diffsyncer_test.go
Normal file
162
common/commonspace/diffservice/diffsyncer_test.go
Normal file
@ -0,0 +1,162 @@
|
||||
package diffservice
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache/mock_cache"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/remotediff"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto/mock_spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage/mock_storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf/mock_nodeconf"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclrecordproto"
|
||||
mock_aclstorage "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage/mock_storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff/mock_ldiff"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"storj.io/drpc"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type pushSpaceRequestMatcher struct {
|
||||
spaceId string
|
||||
aclRoot *aclrecordproto.RawACLRecordWithId
|
||||
spaceHeader *spacesyncproto.SpaceHeader
|
||||
}
|
||||
|
||||
func (p pushSpaceRequestMatcher) Matches(x interface{}) bool {
|
||||
res, ok := x.(*spacesyncproto.PushSpaceRequest)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
return res.SpaceId == p.spaceId && res.AclRoot == p.aclRoot && res.SpaceHeader == p.spaceHeader
|
||||
}
|
||||
|
||||
func (p pushSpaceRequestMatcher) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
type mockPeer struct{}
|
||||
|
||||
func (m mockPeer) Id() string {
|
||||
return "mockId"
|
||||
}
|
||||
|
||||
func (m mockPeer) LastUsage() time.Time {
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
func (m mockPeer) UpdateLastUsage() {
|
||||
}
|
||||
|
||||
func (m mockPeer) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m mockPeer) Closed() <-chan struct{} {
|
||||
return make(chan struct{})
|
||||
}
|
||||
|
||||
func (m mockPeer) Invoke(ctx context.Context, rpc string, enc drpc.Encoding, in, out drpc.Message) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m mockPeer) NewStream(ctx context.Context, rpc string, enc drpc.Encoding) (drpc.Stream, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func newPushSpaceRequestMatcher(
|
||||
spaceId string,
|
||||
aclRoot *aclrecordproto.RawACLRecordWithId,
|
||||
spaceHeader *spacesyncproto.SpaceHeader) *pushSpaceRequestMatcher {
|
||||
return &pushSpaceRequestMatcher{
|
||||
spaceId: spaceId,
|
||||
aclRoot: aclRoot,
|
||||
spaceHeader: spaceHeader,
|
||||
}
|
||||
}
|
||||
|
||||
func TestDiffSyncer_Sync(t *testing.T) {
|
||||
// setup
|
||||
ctx := context.Background()
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
diffMock := mock_ldiff.NewMockDiff(ctrl)
|
||||
connectorMock := mock_nodeconf.NewMockConfConnector(ctrl)
|
||||
cacheMock := mock_cache.NewMockTreeCache(ctrl)
|
||||
stMock := mock_storage.NewMockSpaceStorage(ctrl)
|
||||
clientMock := mock_spacesyncproto.NewMockDRPCSpaceClient(ctrl)
|
||||
factory := spacesyncproto.ClientFactoryFunc(func(cc drpc.Conn) spacesyncproto.DRPCSpaceClient {
|
||||
return clientMock
|
||||
})
|
||||
spaceId := "spaceId"
|
||||
l := logger.NewNamed(spaceId)
|
||||
diffSyncer := newDiffSyncer(spaceId, diffMock, connectorMock, cacheMock, stMock, factory, l)
|
||||
|
||||
t.Run("diff syncer sync simple", func(t *testing.T) {
|
||||
connectorMock.EXPECT().
|
||||
GetResponsiblePeers(gomock.Any(), spaceId).
|
||||
Return([]peer.Peer{mockPeer{}}, nil)
|
||||
diffMock.EXPECT().
|
||||
Diff(gomock.Any(), gomock.Eq(remotediff.NewRemoteDiff(spaceId, clientMock))).
|
||||
Return([]string{"new"}, []string{"changed"}, nil, nil)
|
||||
for _, arg := range []string{"new", "changed"} {
|
||||
cacheMock.EXPECT().
|
||||
GetTree(gomock.Any(), spaceId, arg).
|
||||
Return(cache.TreeResult{}, nil)
|
||||
}
|
||||
require.NoError(t, diffSyncer.Sync(ctx))
|
||||
})
|
||||
|
||||
t.Run("diff syncer sync conf error", func(t *testing.T) {
|
||||
connectorMock.EXPECT().
|
||||
GetResponsiblePeers(gomock.Any(), spaceId).
|
||||
Return(nil, fmt.Errorf("some error"))
|
||||
|
||||
require.Error(t, diffSyncer.Sync(ctx))
|
||||
})
|
||||
|
||||
t.Run("diff syncer sync space missing", func(t *testing.T) {
|
||||
aclStorageMock := mock_aclstorage.NewMockListStorage(ctrl)
|
||||
aclRoot := &aclrecordproto.RawACLRecordWithId{}
|
||||
spaceHeader := &spacesyncproto.SpaceHeader{}
|
||||
|
||||
connectorMock.EXPECT().
|
||||
GetResponsiblePeers(gomock.Any(), spaceId).
|
||||
Return([]peer.Peer{mockPeer{}}, nil)
|
||||
diffMock.EXPECT().
|
||||
Diff(gomock.Any(), gomock.Eq(remotediff.NewRemoteDiff(spaceId, clientMock))).
|
||||
Return(nil, nil, nil, spacesyncproto.ErrSpaceMissing)
|
||||
stMock.EXPECT().
|
||||
ACLStorage().
|
||||
Return(aclStorageMock, nil)
|
||||
stMock.EXPECT().
|
||||
SpaceHeader().
|
||||
Return(spaceHeader, nil)
|
||||
aclStorageMock.EXPECT().
|
||||
Root().
|
||||
Return(aclRoot, nil)
|
||||
clientMock.EXPECT().
|
||||
PushSpace(gomock.Any(), newPushSpaceRequestMatcher(spaceId, aclRoot, spaceHeader)).
|
||||
Return(nil, nil)
|
||||
|
||||
require.NoError(t, diffSyncer.Sync(ctx))
|
||||
})
|
||||
|
||||
t.Run("diff syncer sync other error", func(t *testing.T) {
|
||||
connectorMock.EXPECT().
|
||||
GetResponsiblePeers(gomock.Any(), spaceId).
|
||||
Return([]peer.Peer{mockPeer{}}, nil)
|
||||
diffMock.EXPECT().
|
||||
Diff(gomock.Any(), gomock.Eq(remotediff.NewRemoteDiff(spaceId, clientMock))).
|
||||
Return(nil, nil, nil, spacesyncproto.ErrUnexpected)
|
||||
|
||||
require.NoError(t, diffSyncer.Sync(ctx))
|
||||
})
|
||||
}
|
||||
@ -0,0 +1,96 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice (interfaces: DiffSyncer,PeriodicSync)
|
||||
|
||||
// Package mock_diffservice is a generated GoMock package.
|
||||
package mock_diffservice
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockDiffSyncer is a mock of DiffSyncer interface.
|
||||
type MockDiffSyncer struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockDiffSyncerMockRecorder
|
||||
}
|
||||
|
||||
// MockDiffSyncerMockRecorder is the mock recorder for MockDiffSyncer.
|
||||
type MockDiffSyncerMockRecorder struct {
|
||||
mock *MockDiffSyncer
|
||||
}
|
||||
|
||||
// NewMockDiffSyncer creates a new mock instance.
|
||||
func NewMockDiffSyncer(ctrl *gomock.Controller) *MockDiffSyncer {
|
||||
mock := &MockDiffSyncer{ctrl: ctrl}
|
||||
mock.recorder = &MockDiffSyncerMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockDiffSyncer) EXPECT() *MockDiffSyncerMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Sync mocks base method.
|
||||
func (m *MockDiffSyncer) Sync(arg0 context.Context) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Sync", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Sync indicates an expected call of Sync.
|
||||
func (mr *MockDiffSyncerMockRecorder) Sync(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Sync", reflect.TypeOf((*MockDiffSyncer)(nil).Sync), arg0)
|
||||
}
|
||||
|
||||
// MockPeriodicSync is a mock of PeriodicSync interface.
|
||||
type MockPeriodicSync struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockPeriodicSyncMockRecorder
|
||||
}
|
||||
|
||||
// MockPeriodicSyncMockRecorder is the mock recorder for MockPeriodicSync.
|
||||
type MockPeriodicSyncMockRecorder struct {
|
||||
mock *MockPeriodicSync
|
||||
}
|
||||
|
||||
// NewMockPeriodicSync creates a new mock instance.
|
||||
func NewMockPeriodicSync(ctrl *gomock.Controller) *MockPeriodicSync {
|
||||
mock := &MockPeriodicSync{ctrl: ctrl}
|
||||
mock.recorder = &MockPeriodicSyncMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockPeriodicSync) EXPECT() *MockPeriodicSyncMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Close mocks base method.
|
||||
func (m *MockPeriodicSync) Close() {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "Close")
|
||||
}
|
||||
|
||||
// Close indicates an expected call of Close.
|
||||
func (mr *MockPeriodicSyncMockRecorder) Close() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockPeriodicSync)(nil).Close))
|
||||
}
|
||||
|
||||
// Run mocks base method.
|
||||
func (m *MockPeriodicSync) Run() {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "Run")
|
||||
}
|
||||
|
||||
// Run indicates an expected call of Run.
|
||||
func (mr *MockPeriodicSyncMockRecorder) Run() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Run", reflect.TypeOf((*MockPeriodicSync)(nil).Run))
|
||||
}
|
||||
@ -6,25 +6,34 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func newPeriodicSync(periodSeconds int, sync func(ctx context.Context) error, l *zap.Logger) *periodicSync {
|
||||
type PeriodicSync interface {
|
||||
Run()
|
||||
Close()
|
||||
}
|
||||
|
||||
func newPeriodicSync(periodSeconds int, syncer DiffSyncer, l *zap.Logger) *periodicSync {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ps := &periodicSync{
|
||||
log: l,
|
||||
sync: sync,
|
||||
syncCtx: ctx,
|
||||
syncCancel: cancel,
|
||||
syncLoopDone: make(chan struct{}),
|
||||
return &periodicSync{
|
||||
syncer: syncer,
|
||||
log: l,
|
||||
syncCtx: ctx,
|
||||
syncCancel: cancel,
|
||||
syncLoopDone: make(chan struct{}),
|
||||
periodSeconds: periodSeconds,
|
||||
}
|
||||
go ps.syncLoop(periodSeconds)
|
||||
return ps
|
||||
}
|
||||
|
||||
type periodicSync struct {
|
||||
log *zap.Logger
|
||||
sync func(ctx context.Context) error
|
||||
syncCtx context.Context
|
||||
syncCancel context.CancelFunc
|
||||
syncLoopDone chan struct{}
|
||||
log *zap.Logger
|
||||
syncer DiffSyncer
|
||||
syncCtx context.Context
|
||||
syncCancel context.CancelFunc
|
||||
syncLoopDone chan struct{}
|
||||
periodSeconds int
|
||||
}
|
||||
|
||||
func (p *periodicSync) Run() {
|
||||
go p.syncLoop(p.periodSeconds)
|
||||
}
|
||||
|
||||
func (p *periodicSync) syncLoop(periodSeconds int) {
|
||||
@ -33,7 +42,7 @@ func (p *periodicSync) syncLoop(periodSeconds int) {
|
||||
doSync := func() {
|
||||
ctx, cancel := context.WithTimeout(p.syncCtx, time.Minute)
|
||||
defer cancel()
|
||||
if err := p.sync(ctx); err != nil {
|
||||
if err := p.syncer.Sync(ctx); err != nil {
|
||||
p.log.Warn("periodic sync error", zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
38
common/commonspace/diffservice/periodicsync_test.go
Normal file
38
common/commonspace/diffservice/periodicsync_test.go
Normal file
@ -0,0 +1,38 @@
|
||||
package diffservice
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice/mock_diffservice"
|
||||
"github.com/golang/mock/gomock"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestPeriodicSync_Run(t *testing.T) {
|
||||
// setup
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
l := logger.NewNamed("sync")
|
||||
diffSyncer := mock_diffservice.NewMockDiffSyncer(ctrl)
|
||||
t.Run("diff syncer 1 time", func(t *testing.T) {
|
||||
secs := 0
|
||||
pSync := newPeriodicSync(secs, diffSyncer, l)
|
||||
|
||||
diffSyncer.EXPECT().Sync(gomock.Any()).Times(1).Return(nil)
|
||||
|
||||
pSync.Run()
|
||||
pSync.Close()
|
||||
})
|
||||
|
||||
t.Run("diff syncer 2 times", func(t *testing.T) {
|
||||
secs := 1
|
||||
|
||||
pSync := newPeriodicSync(secs, diffSyncer, l)
|
||||
diffSyncer.EXPECT().Sync(gomock.Any()).Times(2).Return(nil)
|
||||
|
||||
pSync.Run()
|
||||
time.Sleep(time.Second * time.Duration(secs))
|
||||
pSync.Close()
|
||||
})
|
||||
}
|
||||
193
common/commonspace/payloads.go
Normal file
193
common/commonspace/payloads.go
Normal file
@ -0,0 +1,193 @@
|
||||
package commonspace
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclrecordproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/cid"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/signingkey"
|
||||
"hash/fnv"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
func storagePayloadForSpaceCreate(payload SpaceCreatePayload) (storagePayload storage.SpaceStorageCreatePayload, err error) {
|
||||
// unmarshalling signing and encryption keys
|
||||
identity, err := payload.SigningKey.GetPublic().Raw()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
encPubKey, err := payload.EncryptionKey.GetPublic().Raw()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// preparing header and space id
|
||||
bytes := make([]byte, 32)
|
||||
_, err = rand.Read(bytes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
header := &spacesyncproto.SpaceHeader{
|
||||
Identity: identity,
|
||||
Timestamp: time.Now().UnixNano(),
|
||||
SpaceType: payload.SpaceType,
|
||||
ReplicationKey: payload.ReplicationKey,
|
||||
Seed: bytes,
|
||||
}
|
||||
marshalled, err := header.Marshal()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
id, err := cid.NewCIDFromBytes(marshalled)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
spaceId := NewSpaceId(id, payload.ReplicationKey)
|
||||
|
||||
// encrypting read key
|
||||
hasher := fnv.New64()
|
||||
_, err = hasher.Write(payload.ReadKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
readKeyHash := hasher.Sum64()
|
||||
encReadKey, err := payload.EncryptionKey.GetPublic().Encrypt(payload.ReadKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// preparing acl
|
||||
aclRoot := &aclrecordproto.ACLRoot{
|
||||
Identity: identity,
|
||||
EncryptionKey: encPubKey,
|
||||
SpaceId: spaceId,
|
||||
EncryptedReadKey: encReadKey,
|
||||
DerivationScheme: "",
|
||||
CurrentReadKeyHash: readKeyHash,
|
||||
Timestamp: time.Now().UnixNano(),
|
||||
}
|
||||
rawWithId, err := marshalACLRoot(aclRoot, payload.SigningKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// creating storage
|
||||
storagePayload = storage.SpaceStorageCreatePayload{
|
||||
RecWithId: rawWithId,
|
||||
SpaceHeader: header,
|
||||
Id: id,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func storagePayloadForSpaceDerive(payload SpaceDerivePayload) (storagePayload storage.SpaceStorageCreatePayload, err error) {
|
||||
// unmarshalling signing and encryption keys
|
||||
identity, err := payload.SigningKey.GetPublic().Raw()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
signPrivKey, err := payload.SigningKey.Raw()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
encPubKey, err := payload.EncryptionKey.GetPublic().Raw()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
encPrivKey, err := payload.EncryptionKey.Raw()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// preparing replication key
|
||||
hasher := fnv.New64()
|
||||
_, err = hasher.Write(identity)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
repKey := hasher.Sum64()
|
||||
|
||||
// preparing header and space id
|
||||
header := &spacesyncproto.SpaceHeader{
|
||||
Identity: identity,
|
||||
SpaceType: SpaceTypeDerived,
|
||||
ReplicationKey: repKey,
|
||||
}
|
||||
marshalled, err := header.Marshal()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
id, err := cid.NewCIDFromBytes(marshalled)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
spaceId := NewSpaceId(id, repKey)
|
||||
|
||||
// deriving and encrypting read key
|
||||
readKey, err := aclrecordproto.ACLReadKeyDerive(signPrivKey, encPrivKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
hasher = fnv.New64()
|
||||
_, err = hasher.Write(readKey.Bytes())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
readKeyHash := hasher.Sum64()
|
||||
encReadKey, err := payload.EncryptionKey.GetPublic().Encrypt(readKey.Bytes())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// preparing acl
|
||||
aclRoot := &aclrecordproto.ACLRoot{
|
||||
Identity: identity,
|
||||
EncryptionKey: encPubKey,
|
||||
SpaceId: spaceId,
|
||||
EncryptedReadKey: encReadKey,
|
||||
DerivationScheme: "",
|
||||
CurrentReadKeyHash: readKeyHash,
|
||||
Timestamp: time.Now().UnixNano(),
|
||||
}
|
||||
rawWithId, err := marshalACLRoot(aclRoot, payload.SigningKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// creating storage
|
||||
storagePayload = storage.SpaceStorageCreatePayload{
|
||||
RecWithId: rawWithId,
|
||||
SpaceHeader: header,
|
||||
Id: id,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func marshalACLRoot(aclRoot *aclrecordproto.ACLRoot, key signingkey.PrivKey) (rawWithId *aclrecordproto.RawACLRecordWithId, err error) {
|
||||
marshalledRoot, err := aclRoot.Marshal()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
signature, err := key.Sign(marshalledRoot)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
raw := &aclrecordproto.RawACLRecord{
|
||||
Payload: marshalledRoot,
|
||||
Signature: signature,
|
||||
}
|
||||
marshalledRaw, err := raw.Marshal()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
aclHeadId, err := cid.NewCIDFromBytes(marshalledRaw)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
rawWithId = &aclrecordproto.RawACLRecordWithId{
|
||||
Payload: marshalledRaw,
|
||||
Id: aclHeadId,
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -19,5 +19,5 @@ func (r *rpcHandler) HeadSync(ctx context.Context, req *spacesyncproto.HeadSyncR
|
||||
}
|
||||
|
||||
func (r *rpcHandler) Stream(stream spacesyncproto.DRPCSpace_StreamStream) (err error) {
|
||||
return r.s.SyncService().StreamPool().AddAndReadStreamSync(stream)
|
||||
return r.s.SyncService().SyncClient().AddAndReadStreamSync(stream)
|
||||
}
|
||||
|
||||
@ -6,17 +6,11 @@ import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/pool"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/config"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclrecordproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/cid"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/signingkey"
|
||||
"hash/fnv"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
const CName = "common.commonspace"
|
||||
@ -39,6 +33,7 @@ type service struct {
|
||||
configurationService nodeconf.Service
|
||||
storageProvider storage.SpaceStorageProvider
|
||||
cache cache.TreeCache
|
||||
pool pool.Pool
|
||||
}
|
||||
|
||||
func (s *service) Init(a *app.App) (err error) {
|
||||
@ -46,6 +41,7 @@ func (s *service) Init(a *app.App) (err error) {
|
||||
s.storageProvider = a.MustComponent(storage.CName).(storage.SpaceStorageProvider)
|
||||
s.configurationService = a.MustComponent(nodeconf.CName).(nodeconf.Service)
|
||||
s.cache = a.MustComponent(cache.CName).(cache.TreeCache)
|
||||
s.pool = a.MustComponent(pool.CName).(pool.Pool)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -57,171 +53,32 @@ func (s *service) CreateSpace(
|
||||
ctx context.Context,
|
||||
cache cache.TreeCache,
|
||||
payload SpaceCreatePayload) (sp Space, err error) {
|
||||
|
||||
// unmarshalling signing and encryption keys
|
||||
identity, err := payload.SigningKey.GetPublic().Raw()
|
||||
storageCreate, err := storagePayloadForSpaceCreate(payload)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
encPubKey, err := payload.EncryptionKey.GetPublic().Raw()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// preparing header and space id
|
||||
bytes := make([]byte, 32)
|
||||
_, err = rand.Read(bytes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
header := &spacesyncproto.SpaceHeader{
|
||||
Identity: identity,
|
||||
Timestamp: time.Now().UnixNano(),
|
||||
SpaceType: payload.SpaceType,
|
||||
ReplicationKey: payload.ReplicationKey,
|
||||
Seed: bytes,
|
||||
}
|
||||
marshalled, err := header.Marshal()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
id, err := cid.NewCIDFromBytes(marshalled)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
spaceId := NewSpaceId(id, payload.ReplicationKey)
|
||||
|
||||
// encrypting read key
|
||||
hasher := fnv.New64()
|
||||
_, err = hasher.Write(payload.ReadKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
readKeyHash := hasher.Sum64()
|
||||
encReadKey, err := payload.EncryptionKey.GetPublic().Encrypt(payload.ReadKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// preparing acl
|
||||
aclRoot := &aclrecordproto.ACLRoot{
|
||||
Identity: identity,
|
||||
EncryptionKey: encPubKey,
|
||||
SpaceId: spaceId,
|
||||
EncryptedReadKey: encReadKey,
|
||||
DerivationScheme: "",
|
||||
CurrentReadKeyHash: readKeyHash,
|
||||
Timestamp: time.Now().UnixNano(),
|
||||
}
|
||||
rawWithId, err := marshalACLRoot(aclRoot, payload.SigningKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// creating storage
|
||||
storageCreate := storage.SpaceStorageCreatePayload{
|
||||
RecWithId: rawWithId,
|
||||
SpaceHeader: header,
|
||||
Id: id,
|
||||
}
|
||||
_, err = s.storageProvider.CreateSpaceStorage(storageCreate)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return s.GetSpace(ctx, spaceId)
|
||||
return s.GetSpace(ctx, storageCreate.Id)
|
||||
}
|
||||
|
||||
func (s *service) DeriveSpace(
|
||||
ctx context.Context,
|
||||
cache cache.TreeCache,
|
||||
payload SpaceDerivePayload) (sp Space, err error) {
|
||||
|
||||
// unmarshalling signing and encryption keys
|
||||
identity, err := payload.SigningKey.GetPublic().Raw()
|
||||
storageCreate, err := storagePayloadForSpaceDerive(payload)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
signPrivKey, err := payload.SigningKey.Raw()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
encPubKey, err := payload.EncryptionKey.GetPublic().Raw()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
encPrivKey, err := payload.EncryptionKey.Raw()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// preparing replication key
|
||||
hasher := fnv.New64()
|
||||
_, err = hasher.Write(identity)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
repKey := hasher.Sum64()
|
||||
|
||||
// preparing header and space id
|
||||
header := &spacesyncproto.SpaceHeader{
|
||||
Identity: identity,
|
||||
SpaceType: SpaceTypeDerived,
|
||||
ReplicationKey: repKey,
|
||||
}
|
||||
marshalled, err := header.Marshal()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
id, err := cid.NewCIDFromBytes(marshalled)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
spaceId := NewSpaceId(id, repKey)
|
||||
|
||||
// deriving and encrypting read key
|
||||
readKey, err := aclrecordproto.ACLReadKeyDerive(signPrivKey, encPrivKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
hasher = fnv.New64()
|
||||
_, err = hasher.Write(readKey.Bytes())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
readKeyHash := hasher.Sum64()
|
||||
encReadKey, err := payload.EncryptionKey.GetPublic().Encrypt(readKey.Bytes())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// preparing acl
|
||||
aclRoot := &aclrecordproto.ACLRoot{
|
||||
Identity: identity,
|
||||
EncryptionKey: encPubKey,
|
||||
SpaceId: spaceId,
|
||||
EncryptedReadKey: encReadKey,
|
||||
DerivationScheme: "",
|
||||
CurrentReadKeyHash: readKeyHash,
|
||||
Timestamp: time.Now().UnixNano(),
|
||||
}
|
||||
rawWithId, err := marshalACLRoot(aclRoot, payload.SigningKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// creating storage
|
||||
storageCreate := storage.SpaceStorageCreatePayload{
|
||||
RecWithId: rawWithId,
|
||||
SpaceHeader: header,
|
||||
Id: id,
|
||||
}
|
||||
_, err = s.storageProvider.CreateSpaceStorage(storageCreate)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return s.GetSpace(ctx, spaceId)
|
||||
return s.GetSpace(ctx, storageCreate.Id)
|
||||
}
|
||||
|
||||
func (s *service) GetSpace(ctx context.Context, id string) (Space, error) {
|
||||
@ -230,8 +87,9 @@ func (s *service) GetSpace(ctx context.Context, id string) (Space, error) {
|
||||
return nil, err
|
||||
}
|
||||
lastConfiguration := s.configurationService.GetLast()
|
||||
diffService := diffservice.NewDiffService(id, s.config.SyncPeriod, st, lastConfiguration, s.cache, log)
|
||||
syncService := syncservice.NewSyncService(id, diffService, s.cache, lastConfiguration)
|
||||
confConnector := nodeconf.NewConfConnector(lastConfiguration, s.pool)
|
||||
diffService := diffservice.NewDiffService(id, s.config.SyncPeriod, st, confConnector, s.cache, log)
|
||||
syncService := syncservice.NewSyncService(id, diffService, s.cache, lastConfiguration, confConnector)
|
||||
sp := &space{
|
||||
id: id,
|
||||
syncService: syncService,
|
||||
@ -244,31 +102,3 @@ func (s *service) GetSpace(ctx context.Context, id string) (Space, error) {
|
||||
}
|
||||
return sp, nil
|
||||
}
|
||||
|
||||
func marshalACLRoot(aclRoot *aclrecordproto.ACLRoot, key signingkey.PrivKey) (rawWithId *aclrecordproto.RawACLRecordWithId, err error) {
|
||||
marshalledRoot, err := aclRoot.Marshal()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
signature, err := key.Sign(marshalledRoot)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
raw := &aclrecordproto.RawACLRecord{
|
||||
Payload: marshalledRoot,
|
||||
Signature: signature,
|
||||
}
|
||||
marshalledRaw, err := raw.Marshal()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
aclHeadId, err := cid.NewCIDFromBytes(marshalledRaw)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
rawWithId = &aclrecordproto.RawACLRecordWithId{
|
||||
Payload: marshalledRaw,
|
||||
Id: aclHeadId,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -90,11 +90,11 @@ func (s *space) DiffService() diffservice.DiffService {
|
||||
}
|
||||
|
||||
func (s *space) DeriveTree(ctx context.Context, payload tree.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tree.ObjectTree, error) {
|
||||
return synctree.DeriveSyncTree(ctx, payload, s.syncService, listener, s.aclList, s.storage.CreateTreeStorage)
|
||||
return synctree.DeriveSyncTree(ctx, payload, s.syncService.SyncClient(), listener, s.aclList, s.storage.CreateTreeStorage)
|
||||
}
|
||||
|
||||
func (s *space) CreateTree(ctx context.Context, payload tree.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tree.ObjectTree, error) {
|
||||
return synctree.CreateSyncTree(ctx, payload, s.syncService, listener, s.aclList, s.storage.CreateTreeStorage)
|
||||
return synctree.CreateSyncTree(ctx, payload, s.syncService.SyncClient(), listener, s.aclList, s.storage.CreateTreeStorage)
|
||||
}
|
||||
|
||||
func (s *space) BuildTree(ctx context.Context, id string, listener updatelistener.UpdateListener) (t tree.ObjectTree, err error) {
|
||||
@ -104,10 +104,9 @@ func (s *space) BuildTree(ctx context.Context, id string, listener updatelistene
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.syncService.StreamPool().SendSync(
|
||||
return s.syncService.SyncClient().SendSync(
|
||||
peerId,
|
||||
spacesyncproto.WrapFullRequest(&spacesyncproto.ObjectFullSyncRequest{}, nil, id, ""),
|
||||
s.syncService.SyncClient().CreateNewTreeRequest(id),
|
||||
)
|
||||
}
|
||||
|
||||
@ -142,7 +141,7 @@ func (s *space) BuildTree(ctx context.Context, id string, listener updatelistene
|
||||
return
|
||||
}
|
||||
}
|
||||
return synctree.BuildSyncTree(ctx, s.syncService, store.(treestorage.TreeStorage), listener, s.aclList)
|
||||
return synctree.BuildSyncTree(ctx, s.syncService.SyncClient(), store.(treestorage.TreeStorage), listener, s.aclList)
|
||||
}
|
||||
|
||||
func (s *space) Close() error {
|
||||
|
||||
@ -0,0 +1,96 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto (interfaces: DRPCSpaceClient)
|
||||
|
||||
// Package mock_spacesyncproto is a generated GoMock package.
|
||||
package mock_spacesyncproto
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
spacesyncproto "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
drpc "storj.io/drpc"
|
||||
)
|
||||
|
||||
// MockDRPCSpaceClient is a mock of DRPCSpaceClient interface.
|
||||
type MockDRPCSpaceClient struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockDRPCSpaceClientMockRecorder
|
||||
}
|
||||
|
||||
// MockDRPCSpaceClientMockRecorder is the mock recorder for MockDRPCSpaceClient.
|
||||
type MockDRPCSpaceClientMockRecorder struct {
|
||||
mock *MockDRPCSpaceClient
|
||||
}
|
||||
|
||||
// NewMockDRPCSpaceClient creates a new mock instance.
|
||||
func NewMockDRPCSpaceClient(ctrl *gomock.Controller) *MockDRPCSpaceClient {
|
||||
mock := &MockDRPCSpaceClient{ctrl: ctrl}
|
||||
mock.recorder = &MockDRPCSpaceClientMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockDRPCSpaceClient) EXPECT() *MockDRPCSpaceClientMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// DRPCConn mocks base method.
|
||||
func (m *MockDRPCSpaceClient) DRPCConn() drpc.Conn {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DRPCConn")
|
||||
ret0, _ := ret[0].(drpc.Conn)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// DRPCConn indicates an expected call of DRPCConn.
|
||||
func (mr *MockDRPCSpaceClientMockRecorder) DRPCConn() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DRPCConn", reflect.TypeOf((*MockDRPCSpaceClient)(nil).DRPCConn))
|
||||
}
|
||||
|
||||
// HeadSync mocks base method.
|
||||
func (m *MockDRPCSpaceClient) HeadSync(arg0 context.Context, arg1 *spacesyncproto.HeadSyncRequest) (*spacesyncproto.HeadSyncResponse, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "HeadSync", arg0, arg1)
|
||||
ret0, _ := ret[0].(*spacesyncproto.HeadSyncResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// HeadSync indicates an expected call of HeadSync.
|
||||
func (mr *MockDRPCSpaceClientMockRecorder) HeadSync(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeadSync", reflect.TypeOf((*MockDRPCSpaceClient)(nil).HeadSync), arg0, arg1)
|
||||
}
|
||||
|
||||
// PushSpace mocks base method.
|
||||
func (m *MockDRPCSpaceClient) PushSpace(arg0 context.Context, arg1 *spacesyncproto.PushSpaceRequest) (*spacesyncproto.PushSpaceResponse, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "PushSpace", arg0, arg1)
|
||||
ret0, _ := ret[0].(*spacesyncproto.PushSpaceResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// PushSpace indicates an expected call of PushSpace.
|
||||
func (mr *MockDRPCSpaceClientMockRecorder) PushSpace(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PushSpace", reflect.TypeOf((*MockDRPCSpaceClient)(nil).PushSpace), arg0, arg1)
|
||||
}
|
||||
|
||||
// Stream mocks base method.
|
||||
func (m *MockDRPCSpaceClient) Stream(arg0 context.Context) (spacesyncproto.DRPCSpace_StreamClient, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Stream", arg0)
|
||||
ret0, _ := ret[0].(spacesyncproto.DRPCSpace_StreamClient)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Stream indicates an expected call of Stream.
|
||||
func (mr *MockDRPCSpaceClientMockRecorder) Stream(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stream", reflect.TypeOf((*MockDRPCSpaceClient)(nil).Stream), arg0)
|
||||
}
|
||||
@ -1,9 +1,23 @@
|
||||
//go:generate mockgen -destination mock_spacesyncproto/mock_spacesyncproto.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto DRPCSpaceClient
|
||||
package spacesyncproto
|
||||
|
||||
import "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto"
|
||||
import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto"
|
||||
"storj.io/drpc"
|
||||
)
|
||||
|
||||
type SpaceStream = DRPCSpace_StreamStream
|
||||
|
||||
type ClientFactoryFunc func(cc drpc.Conn) DRPCSpaceClient
|
||||
|
||||
func (c ClientFactoryFunc) Client(cc drpc.Conn) DRPCSpaceClient {
|
||||
return c(cc)
|
||||
}
|
||||
|
||||
type ClientFactory interface {
|
||||
Client(cc drpc.Conn) DRPCSpaceClient
|
||||
}
|
||||
|
||||
func WrapHeadUpdate(update *ObjectHeadUpdate, rootChange *treechangeproto.RawTreeChangeWithId, treeId, trackingId string) *ObjectSyncMessage {
|
||||
return &ObjectSyncMessage{
|
||||
Content: &ObjectSyncContentValue{
|
||||
|
||||
194
common/commonspace/storage/mock_storage/mock_storage.go
Normal file
194
common/commonspace/storage/mock_storage/mock_storage.go
Normal file
@ -0,0 +1,194 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage (interfaces: SpaceStorageProvider,SpaceStorage)
|
||||
|
||||
// Package mock_storage is a generated GoMock package.
|
||||
package mock_storage
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
app "github.com/anytypeio/go-anytype-infrastructure-experiments/app"
|
||||
spacesyncproto "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
storage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
|
||||
storage0 "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockSpaceStorageProvider is a mock of SpaceStorageProvider interface.
|
||||
type MockSpaceStorageProvider struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockSpaceStorageProviderMockRecorder
|
||||
}
|
||||
|
||||
// MockSpaceStorageProviderMockRecorder is the mock recorder for MockSpaceStorageProvider.
|
||||
type MockSpaceStorageProviderMockRecorder struct {
|
||||
mock *MockSpaceStorageProvider
|
||||
}
|
||||
|
||||
// NewMockSpaceStorageProvider creates a new mock instance.
|
||||
func NewMockSpaceStorageProvider(ctrl *gomock.Controller) *MockSpaceStorageProvider {
|
||||
mock := &MockSpaceStorageProvider{ctrl: ctrl}
|
||||
mock.recorder = &MockSpaceStorageProviderMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockSpaceStorageProvider) EXPECT() *MockSpaceStorageProviderMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// CreateSpaceStorage mocks base method.
|
||||
func (m *MockSpaceStorageProvider) CreateSpaceStorage(arg0 storage.SpaceStorageCreatePayload) (storage.SpaceStorage, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateSpaceStorage", arg0)
|
||||
ret0, _ := ret[0].(storage.SpaceStorage)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// CreateSpaceStorage indicates an expected call of CreateSpaceStorage.
|
||||
func (mr *MockSpaceStorageProviderMockRecorder) CreateSpaceStorage(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateSpaceStorage", reflect.TypeOf((*MockSpaceStorageProvider)(nil).CreateSpaceStorage), arg0)
|
||||
}
|
||||
|
||||
// Init mocks base method.
|
||||
func (m *MockSpaceStorageProvider) 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 *MockSpaceStorageProviderMockRecorder) Init(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Init", reflect.TypeOf((*MockSpaceStorageProvider)(nil).Init), arg0)
|
||||
}
|
||||
|
||||
// Name mocks base method.
|
||||
func (m *MockSpaceStorageProvider) 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 *MockSpaceStorageProviderMockRecorder) Name() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockSpaceStorageProvider)(nil).Name))
|
||||
}
|
||||
|
||||
// SpaceStorage mocks base method.
|
||||
func (m *MockSpaceStorageProvider) SpaceStorage(arg0 string) (storage.SpaceStorage, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SpaceStorage", arg0)
|
||||
ret0, _ := ret[0].(storage.SpaceStorage)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// SpaceStorage indicates an expected call of SpaceStorage.
|
||||
func (mr *MockSpaceStorageProviderMockRecorder) SpaceStorage(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpaceStorage", reflect.TypeOf((*MockSpaceStorageProvider)(nil).SpaceStorage), arg0)
|
||||
}
|
||||
|
||||
// MockSpaceStorage is a mock of SpaceStorage interface.
|
||||
type MockSpaceStorage struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockSpaceStorageMockRecorder
|
||||
}
|
||||
|
||||
// MockSpaceStorageMockRecorder is the mock recorder for MockSpaceStorage.
|
||||
type MockSpaceStorageMockRecorder struct {
|
||||
mock *MockSpaceStorage
|
||||
}
|
||||
|
||||
// NewMockSpaceStorage creates a new mock instance.
|
||||
func NewMockSpaceStorage(ctrl *gomock.Controller) *MockSpaceStorage {
|
||||
mock := &MockSpaceStorage{ctrl: ctrl}
|
||||
mock.recorder = &MockSpaceStorageMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockSpaceStorage) EXPECT() *MockSpaceStorageMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// ACLStorage mocks base method.
|
||||
func (m *MockSpaceStorage) ACLStorage() (storage0.ListStorage, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ACLStorage")
|
||||
ret0, _ := ret[0].(storage0.ListStorage)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ACLStorage indicates an expected call of ACLStorage.
|
||||
func (mr *MockSpaceStorageMockRecorder) ACLStorage() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ACLStorage", reflect.TypeOf((*MockSpaceStorage)(nil).ACLStorage))
|
||||
}
|
||||
|
||||
// CreateTreeStorage mocks base method.
|
||||
func (m *MockSpaceStorage) CreateTreeStorage(arg0 storage0.TreeStorageCreatePayload) (storage0.TreeStorage, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateTreeStorage", arg0)
|
||||
ret0, _ := ret[0].(storage0.TreeStorage)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// CreateTreeStorage indicates an expected call of CreateTreeStorage.
|
||||
func (mr *MockSpaceStorageMockRecorder) CreateTreeStorage(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateTreeStorage", reflect.TypeOf((*MockSpaceStorage)(nil).CreateTreeStorage), arg0)
|
||||
}
|
||||
|
||||
// SpaceHeader mocks base method.
|
||||
func (m *MockSpaceStorage) SpaceHeader() (*spacesyncproto.SpaceHeader, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SpaceHeader")
|
||||
ret0, _ := ret[0].(*spacesyncproto.SpaceHeader)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// SpaceHeader indicates an expected call of SpaceHeader.
|
||||
func (mr *MockSpaceStorageMockRecorder) SpaceHeader() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpaceHeader", reflect.TypeOf((*MockSpaceStorage)(nil).SpaceHeader))
|
||||
}
|
||||
|
||||
// StoredIds mocks base method.
|
||||
func (m *MockSpaceStorage) StoredIds() ([]string, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "StoredIds")
|
||||
ret0, _ := ret[0].([]string)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// StoredIds indicates an expected call of StoredIds.
|
||||
func (mr *MockSpaceStorageMockRecorder) StoredIds() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StoredIds", reflect.TypeOf((*MockSpaceStorage)(nil).StoredIds))
|
||||
}
|
||||
|
||||
// TreeStorage mocks base method.
|
||||
func (m *MockSpaceStorage) TreeStorage(arg0 string) (storage0.TreeStorage, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "TreeStorage", arg0)
|
||||
ret0, _ := ret[0].(storage0.TreeStorage)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// TreeStorage indicates an expected call of TreeStorage.
|
||||
func (mr *MockSpaceStorageMockRecorder) TreeStorage(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TreeStorage", reflect.TypeOf((*MockSpaceStorage)(nil).TreeStorage), arg0)
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
//go:generate mockgen -destination mock_storage/mock_storage.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage SpaceStorageProvider,SpaceStorage
|
||||
package storage
|
||||
|
||||
import (
|
||||
|
||||
@ -0,0 +1,206 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice (interfaces: SyncClient)
|
||||
|
||||
// Package mock_syncservice is a generated GoMock package.
|
||||
package mock_syncservice
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
spacesyncproto "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
tree "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree"
|
||||
treechangeproto "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockSyncClient is a mock of SyncClient interface.
|
||||
type MockSyncClient struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockSyncClientMockRecorder
|
||||
}
|
||||
|
||||
// MockSyncClientMockRecorder is the mock recorder for MockSyncClient.
|
||||
type MockSyncClientMockRecorder struct {
|
||||
mock *MockSyncClient
|
||||
}
|
||||
|
||||
// NewMockSyncClient creates a new mock instance.
|
||||
func NewMockSyncClient(ctrl *gomock.Controller) *MockSyncClient {
|
||||
mock := &MockSyncClient{ctrl: ctrl}
|
||||
mock.recorder = &MockSyncClientMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockSyncClient) EXPECT() *MockSyncClientMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// AddAndReadStreamAsync mocks base method.
|
||||
func (m *MockSyncClient) AddAndReadStreamAsync(arg0 spacesyncproto.DRPCSpace_StreamStream) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "AddAndReadStreamAsync", arg0)
|
||||
}
|
||||
|
||||
// AddAndReadStreamAsync indicates an expected call of AddAndReadStreamAsync.
|
||||
func (mr *MockSyncClientMockRecorder) AddAndReadStreamAsync(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddAndReadStreamAsync", reflect.TypeOf((*MockSyncClient)(nil).AddAndReadStreamAsync), arg0)
|
||||
}
|
||||
|
||||
// AddAndReadStreamSync mocks base method.
|
||||
func (m *MockSyncClient) AddAndReadStreamSync(arg0 spacesyncproto.DRPCSpace_StreamStream) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AddAndReadStreamSync", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// AddAndReadStreamSync indicates an expected call of AddAndReadStreamSync.
|
||||
func (mr *MockSyncClientMockRecorder) AddAndReadStreamSync(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddAndReadStreamSync", reflect.TypeOf((*MockSyncClient)(nil).AddAndReadStreamSync), arg0)
|
||||
}
|
||||
|
||||
// BroadcastAsync mocks base method.
|
||||
func (m *MockSyncClient) BroadcastAsync(arg0 *spacesyncproto.ObjectSyncMessage) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "BroadcastAsync", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// BroadcastAsync indicates an expected call of BroadcastAsync.
|
||||
func (mr *MockSyncClientMockRecorder) BroadcastAsync(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BroadcastAsync", reflect.TypeOf((*MockSyncClient)(nil).BroadcastAsync), arg0)
|
||||
}
|
||||
|
||||
// BroadcastAsyncOrSendResponsible mocks base method.
|
||||
func (m *MockSyncClient) BroadcastAsyncOrSendResponsible(arg0 *spacesyncproto.ObjectSyncMessage) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "BroadcastAsyncOrSendResponsible", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// BroadcastAsyncOrSendResponsible indicates an expected call of BroadcastAsyncOrSendResponsible.
|
||||
func (mr *MockSyncClientMockRecorder) BroadcastAsyncOrSendResponsible(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BroadcastAsyncOrSendResponsible", reflect.TypeOf((*MockSyncClient)(nil).BroadcastAsyncOrSendResponsible), arg0)
|
||||
}
|
||||
|
||||
// Close mocks base method.
|
||||
func (m *MockSyncClient) Close() error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Close")
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Close indicates an expected call of Close.
|
||||
func (mr *MockSyncClientMockRecorder) Close() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockSyncClient)(nil).Close))
|
||||
}
|
||||
|
||||
// CreateFullSyncRequest mocks base method.
|
||||
func (m *MockSyncClient) CreateFullSyncRequest(arg0 tree.ObjectTree, arg1, arg2 []string, arg3 string) (*spacesyncproto.ObjectSyncMessage, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateFullSyncRequest", arg0, arg1, arg2, arg3)
|
||||
ret0, _ := ret[0].(*spacesyncproto.ObjectSyncMessage)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// CreateFullSyncRequest indicates an expected call of CreateFullSyncRequest.
|
||||
func (mr *MockSyncClientMockRecorder) CreateFullSyncRequest(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateFullSyncRequest", reflect.TypeOf((*MockSyncClient)(nil).CreateFullSyncRequest), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// CreateFullSyncResponse mocks base method.
|
||||
func (m *MockSyncClient) CreateFullSyncResponse(arg0 tree.ObjectTree, arg1, arg2 []string, arg3 string) (*spacesyncproto.ObjectSyncMessage, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateFullSyncResponse", arg0, arg1, arg2, arg3)
|
||||
ret0, _ := ret[0].(*spacesyncproto.ObjectSyncMessage)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// CreateFullSyncResponse indicates an expected call of CreateFullSyncResponse.
|
||||
func (mr *MockSyncClientMockRecorder) CreateFullSyncResponse(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateFullSyncResponse", reflect.TypeOf((*MockSyncClient)(nil).CreateFullSyncResponse), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// CreateHeadUpdate mocks base method.
|
||||
func (m *MockSyncClient) CreateHeadUpdate(arg0 tree.ObjectTree, arg1 []*treechangeproto.RawTreeChangeWithId) *spacesyncproto.ObjectSyncMessage {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateHeadUpdate", arg0, arg1)
|
||||
ret0, _ := ret[0].(*spacesyncproto.ObjectSyncMessage)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// CreateHeadUpdate indicates an expected call of CreateHeadUpdate.
|
||||
func (mr *MockSyncClientMockRecorder) CreateHeadUpdate(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateHeadUpdate", reflect.TypeOf((*MockSyncClient)(nil).CreateHeadUpdate), arg0, arg1)
|
||||
}
|
||||
|
||||
// CreateNewTreeRequest mocks base method.
|
||||
func (m *MockSyncClient) CreateNewTreeRequest(arg0 string) *spacesyncproto.ObjectSyncMessage {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateNewTreeRequest", arg0)
|
||||
ret0, _ := ret[0].(*spacesyncproto.ObjectSyncMessage)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// CreateNewTreeRequest indicates an expected call of CreateNewTreeRequest.
|
||||
func (mr *MockSyncClientMockRecorder) CreateNewTreeRequest(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateNewTreeRequest", reflect.TypeOf((*MockSyncClient)(nil).CreateNewTreeRequest), arg0)
|
||||
}
|
||||
|
||||
// HasActiveStream mocks base method.
|
||||
func (m *MockSyncClient) HasActiveStream(arg0 string) bool {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "HasActiveStream", arg0)
|
||||
ret0, _ := ret[0].(bool)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HasActiveStream indicates an expected call of HasActiveStream.
|
||||
func (mr *MockSyncClientMockRecorder) HasActiveStream(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasActiveStream", reflect.TypeOf((*MockSyncClient)(nil).HasActiveStream), arg0)
|
||||
}
|
||||
|
||||
// SendAsync mocks base method.
|
||||
func (m *MockSyncClient) SendAsync(arg0 []string, arg1 *spacesyncproto.ObjectSyncMessage) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SendAsync", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SendAsync indicates an expected call of SendAsync.
|
||||
func (mr *MockSyncClientMockRecorder) SendAsync(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendAsync", reflect.TypeOf((*MockSyncClient)(nil).SendAsync), arg0, arg1)
|
||||
}
|
||||
|
||||
// SendSync mocks base method.
|
||||
func (m *MockSyncClient) SendSync(arg0 string, arg1 *spacesyncproto.ObjectSyncMessage) (*spacesyncproto.ObjectSyncMessage, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SendSync", arg0, arg1)
|
||||
ret0, _ := ret[0].(*spacesyncproto.ObjectSyncMessage)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// SendSync indicates an expected call of SendSync.
|
||||
func (mr *MockSyncClientMockRecorder) SendSync(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendSync", reflect.TypeOf((*MockSyncClient)(nil).SendSync), arg0, arg1)
|
||||
}
|
||||
73
common/commonspace/syncservice/requestfactory.go
Normal file
73
common/commonspace/syncservice/requestfactory.go
Normal file
@ -0,0 +1,73 @@
|
||||
package syncservice
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/slice"
|
||||
)
|
||||
|
||||
type RequestFactory interface {
|
||||
CreateHeadUpdate(t tree.ObjectTree, added []*treechangeproto.RawTreeChangeWithId) (msg *spacesyncproto.ObjectSyncMessage)
|
||||
CreateNewTreeRequest(id string) (msg *spacesyncproto.ObjectSyncMessage)
|
||||
CreateFullSyncRequest(t tree.ObjectTree, theirHeads, theirSnapshotPath []string, trackingId string) (req *spacesyncproto.ObjectSyncMessage, err error)
|
||||
CreateFullSyncResponse(t tree.ObjectTree, theirHeads, theirSnapshotPath []string, trackingId string) (*spacesyncproto.ObjectSyncMessage, error)
|
||||
}
|
||||
|
||||
func newRequestFactory() RequestFactory {
|
||||
return &requestFactory{}
|
||||
}
|
||||
|
||||
type requestFactory struct{}
|
||||
|
||||
func (r *requestFactory) CreateHeadUpdate(t tree.ObjectTree, added []*treechangeproto.RawTreeChangeWithId) (msg *spacesyncproto.ObjectSyncMessage) {
|
||||
return spacesyncproto.WrapHeadUpdate(&spacesyncproto.ObjectHeadUpdate{
|
||||
Heads: t.Heads(),
|
||||
Changes: added,
|
||||
SnapshotPath: t.SnapshotPath(),
|
||||
}, t.Header(), t.ID(), "")
|
||||
}
|
||||
|
||||
func (r *requestFactory) CreateNewTreeRequest(id string) (msg *spacesyncproto.ObjectSyncMessage) {
|
||||
return spacesyncproto.WrapFullRequest(&spacesyncproto.ObjectFullSyncRequest{}, nil, id, "")
|
||||
}
|
||||
|
||||
func (r *requestFactory) CreateFullSyncRequest(t tree.ObjectTree, theirHeads, theirSnapshotPath []string, trackingId string) (msg *spacesyncproto.ObjectSyncMessage, err error) {
|
||||
req := &spacesyncproto.ObjectFullSyncRequest{}
|
||||
if t == nil {
|
||||
return nil, fmt.Errorf("tree should not be empty")
|
||||
}
|
||||
|
||||
req.Heads = t.Heads()
|
||||
req.SnapshotPath = t.SnapshotPath()
|
||||
|
||||
var changesAfterSnapshot []*treechangeproto.RawTreeChangeWithId
|
||||
changesAfterSnapshot, err = t.ChangesAfterCommonSnapshot(theirSnapshotPath, theirHeads)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
req.Changes = changesAfterSnapshot
|
||||
msg = spacesyncproto.WrapFullRequest(req, t.Header(), t.ID(), trackingId)
|
||||
return
|
||||
}
|
||||
|
||||
func (r *requestFactory) CreateFullSyncResponse(t tree.ObjectTree, theirHeads, theirSnapshotPath []string, trackingId string) (msg *spacesyncproto.ObjectSyncMessage, err error) {
|
||||
resp := &spacesyncproto.ObjectFullSyncResponse{
|
||||
Heads: t.Heads(),
|
||||
SnapshotPath: t.SnapshotPath(),
|
||||
}
|
||||
if slice.UnsortedEquals(theirHeads, t.Heads()) {
|
||||
msg = spacesyncproto.WrapFullResponse(resp, t.Header(), t.ID(), trackingId)
|
||||
return
|
||||
}
|
||||
|
||||
ourChanges, err := t.ChangesAfterCommonSnapshot(theirSnapshotPath, theirHeads)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
resp.Changes = ourChanges
|
||||
msg = spacesyncproto.WrapFullResponse(resp, t.Header(), t.ID(), trackingId)
|
||||
return
|
||||
}
|
||||
@ -18,16 +18,16 @@ const maxSimultaneousOperationsPerStream = 10
|
||||
|
||||
// StreamPool can be made generic to work with different streams
|
||||
type StreamPool interface {
|
||||
SyncClient
|
||||
Sender
|
||||
AddAndReadStreamSync(stream spacesyncproto.SpaceStream) (err error)
|
||||
AddAndReadStreamAsync(stream spacesyncproto.SpaceStream)
|
||||
HasActiveStream(peerId string) bool
|
||||
Close() (err error)
|
||||
}
|
||||
|
||||
type SyncClient interface {
|
||||
type Sender interface {
|
||||
SendSync(peerId string, message *spacesyncproto.ObjectSyncMessage) (reply *spacesyncproto.ObjectSyncMessage, err error)
|
||||
SendAsync(peerId string, message *spacesyncproto.ObjectSyncMessage) (err error)
|
||||
SendAsync(peers []string, message *spacesyncproto.ObjectSyncMessage) (err error)
|
||||
BroadcastAsync(message *spacesyncproto.ObjectSyncMessage) (err error)
|
||||
}
|
||||
|
||||
@ -56,6 +56,8 @@ func newStreamPool(messageHandler MessageHandler) StreamPool {
|
||||
}
|
||||
|
||||
func (s *streamPool) HasActiveStream(peerId string) (res bool) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
_, err := s.getOrDeleteStream(peerId)
|
||||
return err == nil
|
||||
}
|
||||
@ -73,7 +75,7 @@ func (s *streamPool) SendSync(
|
||||
s.waiters[msg.TrackingId] = waiter
|
||||
s.waitersMx.Unlock()
|
||||
|
||||
err = s.SendAsync(peerId, msg)
|
||||
err = s.SendAsync([]string{peerId}, msg)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -82,18 +84,31 @@ func (s *streamPool) SendSync(
|
||||
return
|
||||
}
|
||||
|
||||
func (s *streamPool) SendAsync(peerId string, message *spacesyncproto.ObjectSyncMessage) (err error) {
|
||||
stream, err := s.getOrDeleteStream(peerId)
|
||||
if err != nil {
|
||||
return
|
||||
func (s *streamPool) SendAsync(peers []string, message *spacesyncproto.ObjectSyncMessage) (err error) {
|
||||
getStreams := func() (streams []spacesyncproto.SpaceStream) {
|
||||
for _, pId := range peers {
|
||||
stream, err := s.getOrDeleteStream(pId)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
streams = append(streams, stream)
|
||||
}
|
||||
return streams
|
||||
}
|
||||
|
||||
return stream.Send(message)
|
||||
s.Lock()
|
||||
streams := getStreams()
|
||||
s.Unlock()
|
||||
|
||||
for _, s := range streams {
|
||||
if len(peers) == 1 {
|
||||
err = s.Send(message)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *streamPool) getOrDeleteStream(id string) (stream spacesyncproto.SpaceStream, err error) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
stream, exists := s.peerStreams[id]
|
||||
if !exists {
|
||||
err = ErrEmptyPeer
|
||||
|
||||
49
common/commonspace/syncservice/syncclient.go
Normal file
49
common/commonspace/syncservice/syncclient.go
Normal file
@ -0,0 +1,49 @@
|
||||
package syncservice
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
|
||||
)
|
||||
|
||||
type SyncClient interface {
|
||||
StreamPool
|
||||
RequestFactory
|
||||
BroadcastAsyncOrSendResponsible(message *spacesyncproto.ObjectSyncMessage) (err error)
|
||||
}
|
||||
|
||||
type syncClient struct {
|
||||
StreamPool
|
||||
RequestFactory
|
||||
spaceId string
|
||||
notifiable HeadNotifiable
|
||||
configuration nodeconf.Configuration
|
||||
}
|
||||
|
||||
func newSyncClient(spaceId string, pool StreamPool, notifiable HeadNotifiable, factory RequestFactory, configuration nodeconf.Configuration) SyncClient {
|
||||
return &syncClient{
|
||||
StreamPool: pool,
|
||||
RequestFactory: factory,
|
||||
notifiable: notifiable,
|
||||
configuration: configuration,
|
||||
spaceId: spaceId,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *syncClient) BroadcastAsync(message *spacesyncproto.ObjectSyncMessage) (err error) {
|
||||
s.notifyIfNeeded(message)
|
||||
return s.BroadcastAsync(message)
|
||||
}
|
||||
|
||||
func (s *syncClient) BroadcastAsyncOrSendResponsible(message *spacesyncproto.ObjectSyncMessage) (err error) {
|
||||
if s.configuration.IsResponsible(s.spaceId) {
|
||||
return s.SendAsync(s.configuration.NodeIds(s.spaceId), message)
|
||||
}
|
||||
return s.BroadcastAsync(message)
|
||||
}
|
||||
|
||||
func (s *syncClient) notifyIfNeeded(message *spacesyncproto.ObjectSyncMessage) {
|
||||
if message.GetContent().GetHeadUpdate() != nil {
|
||||
update := message.GetContent().GetHeadUpdate()
|
||||
s.notifiable.UpdateHeads(message.TreeId, update.Heads)
|
||||
}
|
||||
}
|
||||
@ -5,7 +5,6 @@ import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/slice"
|
||||
)
|
||||
|
||||
@ -31,24 +30,24 @@ func (s *syncHandler) HandleMessage(ctx context.Context, senderId string, msg *s
|
||||
content := msg.GetContent()
|
||||
switch {
|
||||
case content.GetFullSyncRequest() != nil:
|
||||
return s.HandleFullSyncRequest(ctx, senderId, content.GetFullSyncRequest(), msg)
|
||||
return s.handleFullSyncRequest(ctx, senderId, content.GetFullSyncRequest(), msg)
|
||||
case content.GetFullSyncResponse() != nil:
|
||||
return s.HandleFullSyncResponse(ctx, senderId, content.GetFullSyncResponse(), msg)
|
||||
return s.handleFullSyncResponse(ctx, senderId, content.GetFullSyncResponse(), msg)
|
||||
case content.GetHeadUpdate() != nil:
|
||||
return s.HandleHeadUpdate(ctx, senderId, content.GetHeadUpdate(), msg)
|
||||
return s.handleHeadUpdate(ctx, senderId, content.GetHeadUpdate(), msg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *syncHandler) HandleHeadUpdate(
|
||||
func (s *syncHandler) handleHeadUpdate(
|
||||
ctx context.Context,
|
||||
senderId string,
|
||||
update *spacesyncproto.ObjectHeadUpdate,
|
||||
msg *spacesyncproto.ObjectSyncMessage) (err error) {
|
||||
|
||||
var (
|
||||
fullRequest *spacesyncproto.ObjectFullSyncRequest
|
||||
result tree.AddResult
|
||||
fullRequest *spacesyncproto.ObjectSyncMessage
|
||||
isEmptyUpdate = len(update.Changes) == 0
|
||||
)
|
||||
res, err := s.treeCache.GetTree(ctx, s.spaceId, msg.TreeId)
|
||||
if err != nil {
|
||||
@ -61,44 +60,51 @@ func (s *syncHandler) HandleHeadUpdate(
|
||||
defer res.Release()
|
||||
defer objTree.Unlock()
|
||||
|
||||
if slice.UnsortedEquals(update.Heads, objTree.Heads()) {
|
||||
// isEmptyUpdate is sent when the tree is brought up from cache
|
||||
if isEmptyUpdate {
|
||||
if slice.UnsortedEquals(objTree.Heads(), update.Heads) {
|
||||
return nil
|
||||
}
|
||||
// we need to sync in any case
|
||||
fullRequest, err = s.syncClient.CreateFullSyncRequest(objTree, update.Heads, update.SnapshotPath, msg.TrackingId)
|
||||
return err
|
||||
}
|
||||
|
||||
if s.alreadyHasHeads(objTree, update.Heads) {
|
||||
return nil
|
||||
}
|
||||
|
||||
result, err = objTree.AddRawChanges(ctx, update.Changes...)
|
||||
_, err = objTree.AddRawChanges(ctx, update.Changes...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// if we couldn't add all the changes
|
||||
if len(update.Changes) != len(result.Added) {
|
||||
fullRequest, err = s.prepareFullSyncRequest(objTree, update)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if s.alreadyHasHeads(objTree, update.Heads) {
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
|
||||
fullRequest, err = s.syncClient.CreateFullSyncRequest(objTree, update.Heads, update.SnapshotPath, msg.TrackingId)
|
||||
return err
|
||||
}()
|
||||
|
||||
if fullRequest != nil {
|
||||
return s.syncClient.SendAsync(senderId,
|
||||
spacesyncproto.WrapFullRequest(fullRequest, msg.RootChange, msg.TreeId, msg.TrackingId))
|
||||
return s.syncClient.SendAsync([]string{senderId}, fullRequest)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *syncHandler) HandleFullSyncRequest(
|
||||
func (s *syncHandler) handleFullSyncRequest(
|
||||
ctx context.Context,
|
||||
senderId string,
|
||||
request *spacesyncproto.ObjectFullSyncRequest,
|
||||
msg *spacesyncproto.ObjectSyncMessage) (err error) {
|
||||
var (
|
||||
fullResponse *spacesyncproto.ObjectFullSyncResponse
|
||||
fullResponse *spacesyncproto.ObjectSyncMessage
|
||||
header = msg.RootChange
|
||||
)
|
||||
defer func() {
|
||||
if err != nil {
|
||||
s.syncClient.SendAsync(senderId, spacesyncproto.WrapError(err, header, msg.TreeId, msg.TrackingId))
|
||||
s.syncClient.SendAsync([]string{senderId}, spacesyncproto.WrapError(err, header, msg.TreeId, msg.TrackingId))
|
||||
}
|
||||
}()
|
||||
|
||||
@ -117,23 +123,24 @@ func (s *syncHandler) HandleFullSyncRequest(
|
||||
header = objTree.Header()
|
||||
}
|
||||
|
||||
_, err = objTree.AddRawChanges(ctx, request.Changes...)
|
||||
if err != nil {
|
||||
return err
|
||||
if len(request.Changes) != 0 && !s.alreadyHasHeads(objTree, request.Heads) {
|
||||
_, err = objTree.AddRawChanges(ctx, request.Changes...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
fullResponse, err = s.prepareFullSyncResponse(request.SnapshotPath, request.Heads, objTree)
|
||||
fullResponse, err = s.syncClient.CreateFullSyncResponse(objTree, request.Heads, request.SnapshotPath, msg.TrackingId)
|
||||
return err
|
||||
}()
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return s.syncClient.SendAsync(senderId,
|
||||
spacesyncproto.WrapFullResponse(fullResponse, header, msg.TreeId, msg.TrackingId))
|
||||
return s.syncClient.SendAsync([]string{senderId}, fullResponse)
|
||||
}
|
||||
|
||||
func (s *syncHandler) HandleFullSyncResponse(
|
||||
func (s *syncHandler) handleFullSyncResponse(
|
||||
ctx context.Context,
|
||||
senderId string,
|
||||
response *spacesyncproto.ObjectFullSyncResponse,
|
||||
@ -149,8 +156,7 @@ func (s *syncHandler) HandleFullSyncResponse(
|
||||
defer res.Release()
|
||||
defer objTree.Unlock()
|
||||
|
||||
// if we already have the heads for whatever reason
|
||||
if slice.UnsortedEquals(response.Heads, objTree.Heads()) {
|
||||
if s.alreadyHasHeads(objTree, response.Heads) {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -161,39 +167,6 @@ func (s *syncHandler) HandleFullSyncResponse(
|
||||
return
|
||||
}
|
||||
|
||||
func (s *syncHandler) prepareFullSyncRequest(
|
||||
t tree.ObjectTree,
|
||||
update *spacesyncproto.ObjectHeadUpdate) (req *spacesyncproto.ObjectFullSyncRequest, err error) {
|
||||
req = &spacesyncproto.ObjectFullSyncRequest{
|
||||
Heads: t.Heads(),
|
||||
SnapshotPath: t.SnapshotPath(),
|
||||
}
|
||||
if len(update.Changes) != 0 {
|
||||
var changesAfterSnapshot []*treechangeproto.RawTreeChangeWithId
|
||||
changesAfterSnapshot, err = t.ChangesAfterCommonSnapshot(update.SnapshotPath, update.Heads)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
req.Changes = changesAfterSnapshot
|
||||
}
|
||||
return &spacesyncproto.ObjectFullSyncRequest{
|
||||
Heads: t.Heads(),
|
||||
SnapshotPath: t.SnapshotPath(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *syncHandler) prepareFullSyncResponse(
|
||||
theirPath,
|
||||
theirHeads []string,
|
||||
t tree.ObjectTree) (*spacesyncproto.ObjectFullSyncResponse, error) {
|
||||
ourChanges, err := t.ChangesAfterCommonSnapshot(theirPath, theirHeads)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &spacesyncproto.ObjectFullSyncResponse{
|
||||
Heads: t.Heads(),
|
||||
Changes: ourChanges,
|
||||
SnapshotPath: t.SnapshotPath(),
|
||||
}, nil
|
||||
func (s *syncHandler) alreadyHasHeads(t tree.ObjectTree, heads []string) bool {
|
||||
return slice.UnsortedEquals(t.Heads(), heads) || t.HasChanges(heads...)
|
||||
}
|
||||
|
||||
397
common/commonspace/syncservice/synchandler_test.go
Normal file
397
common/commonspace/syncservice/synchandler_test.go
Normal file
@ -0,0 +1,397 @@
|
||||
package syncservice
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache/mock_cache"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice/mock_syncservice"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree"
|
||||
mock_tree "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree/mock_objecttree"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type treeContainer struct {
|
||||
objTree tree.ObjectTree
|
||||
}
|
||||
|
||||
func (t treeContainer) Tree() tree.ObjectTree {
|
||||
return t.objTree
|
||||
}
|
||||
|
||||
type testObjTreeMock struct {
|
||||
*mock_tree.MockObjectTree
|
||||
m sync.Mutex
|
||||
}
|
||||
|
||||
func newTestObjMock(mockTree *mock_tree.MockObjectTree) *testObjTreeMock {
|
||||
return &testObjTreeMock{
|
||||
MockObjectTree: mockTree,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *testObjTreeMock) Lock() {
|
||||
t.m.Lock()
|
||||
}
|
||||
|
||||
func (t *testObjTreeMock) Unlock() {
|
||||
t.m.Unlock()
|
||||
}
|
||||
|
||||
func TestSyncHandler_HandleHeadUpdate(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
ctx := context.Background()
|
||||
spaceId := "spaceId"
|
||||
cacheMock := mock_cache.NewMockTreeCache(ctrl)
|
||||
syncClientMock := mock_syncservice.NewMockSyncClient(ctrl)
|
||||
objectTreeMock := newTestObjMock(mock_tree.NewMockObjectTree(ctrl))
|
||||
|
||||
syncHandler := newSyncHandler(spaceId, cacheMock, syncClientMock)
|
||||
t.Run("head update non empty all heads added", func(t *testing.T) {
|
||||
treeId := "treeId"
|
||||
senderId := "senderId"
|
||||
chWithId := &treechangeproto.RawTreeChangeWithId{}
|
||||
headUpdate := &spacesyncproto.ObjectHeadUpdate{
|
||||
Heads: []string{"h1"},
|
||||
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
|
||||
SnapshotPath: []string{"h1"},
|
||||
}
|
||||
msg := spacesyncproto.WrapHeadUpdate(headUpdate, chWithId, treeId, "")
|
||||
cacheMock.EXPECT().
|
||||
GetTree(gomock.Any(), spaceId, treeId).
|
||||
Return(cache.TreeResult{
|
||||
Release: func() {},
|
||||
TreeContainer: treeContainer{objectTreeMock},
|
||||
}, nil)
|
||||
objectTreeMock.EXPECT().
|
||||
Heads().
|
||||
Return([]string{"h2"})
|
||||
objectTreeMock.EXPECT().
|
||||
HasChanges(gomock.Eq([]string{"h1"})).
|
||||
Return(false)
|
||||
objectTreeMock.EXPECT().
|
||||
AddRawChanges(gomock.Any(), gomock.Eq([]*treechangeproto.RawTreeChangeWithId{chWithId})).
|
||||
Return(tree.AddResult{}, nil)
|
||||
objectTreeMock.EXPECT().
|
||||
Heads().
|
||||
Return([]string{"h2", "h1"})
|
||||
objectTreeMock.EXPECT().
|
||||
HasChanges(gomock.Eq([]string{"h1"})).
|
||||
Return(true)
|
||||
|
||||
err := syncHandler.HandleMessage(ctx, senderId, msg)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("head update non empty heads not added", func(t *testing.T) {
|
||||
treeId := "treeId"
|
||||
senderId := "senderId"
|
||||
chWithId := &treechangeproto.RawTreeChangeWithId{}
|
||||
headUpdate := &spacesyncproto.ObjectHeadUpdate{
|
||||
Heads: []string{"h1"},
|
||||
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
|
||||
SnapshotPath: []string{"h1"},
|
||||
}
|
||||
fullRequest := &spacesyncproto.ObjectSyncMessage{}
|
||||
msg := spacesyncproto.WrapHeadUpdate(headUpdate, chWithId, treeId, "")
|
||||
cacheMock.EXPECT().
|
||||
GetTree(gomock.Any(), spaceId, treeId).
|
||||
Return(cache.TreeResult{
|
||||
Release: func() {},
|
||||
TreeContainer: treeContainer{objectTreeMock},
|
||||
}, nil)
|
||||
objectTreeMock.EXPECT().
|
||||
Heads().
|
||||
Return([]string{"h2"})
|
||||
objectTreeMock.EXPECT().
|
||||
HasChanges(gomock.Eq([]string{"h1"})).
|
||||
Return(false)
|
||||
objectTreeMock.EXPECT().
|
||||
AddRawChanges(gomock.Any(), gomock.Eq([]*treechangeproto.RawTreeChangeWithId{chWithId})).
|
||||
Return(tree.AddResult{}, nil)
|
||||
objectTreeMock.EXPECT().
|
||||
Heads().
|
||||
Return([]string{"h2"})
|
||||
objectTreeMock.EXPECT().
|
||||
HasChanges(gomock.Eq([]string{"h1"})).
|
||||
Return(false)
|
||||
syncClientMock.EXPECT().
|
||||
CreateFullSyncRequest(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"}), gomock.Eq("")).
|
||||
Return(fullRequest, nil)
|
||||
|
||||
syncClientMock.EXPECT().SendAsync(gomock.Eq([]string{senderId}), gomock.Eq(fullRequest))
|
||||
err := syncHandler.HandleMessage(ctx, senderId, msg)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("head update non empty equal heads", func(t *testing.T) {
|
||||
treeId := "treeId"
|
||||
senderId := "senderId"
|
||||
chWithId := &treechangeproto.RawTreeChangeWithId{}
|
||||
headUpdate := &spacesyncproto.ObjectHeadUpdate{
|
||||
Heads: []string{"h1"},
|
||||
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
|
||||
SnapshotPath: []string{"h1"},
|
||||
}
|
||||
msg := spacesyncproto.WrapHeadUpdate(headUpdate, chWithId, treeId, "")
|
||||
cacheMock.EXPECT().
|
||||
GetTree(gomock.Any(), spaceId, treeId).
|
||||
Return(cache.TreeResult{
|
||||
Release: func() {},
|
||||
TreeContainer: treeContainer{objectTreeMock},
|
||||
}, nil)
|
||||
objectTreeMock.EXPECT().
|
||||
Heads().
|
||||
Return([]string{"h1"})
|
||||
|
||||
err := syncHandler.HandleMessage(ctx, senderId, msg)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("head update empty", func(t *testing.T) {
|
||||
treeId := "treeId"
|
||||
senderId := "senderId"
|
||||
chWithId := &treechangeproto.RawTreeChangeWithId{}
|
||||
headUpdate := &spacesyncproto.ObjectHeadUpdate{
|
||||
Heads: []string{"h1"},
|
||||
Changes: nil,
|
||||
SnapshotPath: []string{"h1"},
|
||||
}
|
||||
fullRequest := &spacesyncproto.ObjectSyncMessage{}
|
||||
msg := spacesyncproto.WrapHeadUpdate(headUpdate, chWithId, treeId, "")
|
||||
cacheMock.EXPECT().
|
||||
GetTree(gomock.Any(), spaceId, treeId).
|
||||
Return(cache.TreeResult{
|
||||
Release: func() {},
|
||||
TreeContainer: treeContainer{objectTreeMock},
|
||||
}, nil)
|
||||
objectTreeMock.EXPECT().
|
||||
Heads().
|
||||
Return([]string{"h2"})
|
||||
syncClientMock.EXPECT().
|
||||
CreateFullSyncRequest(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"}), gomock.Eq("")).
|
||||
Return(fullRequest, nil)
|
||||
|
||||
syncClientMock.EXPECT().SendAsync(gomock.Eq([]string{senderId}), gomock.Eq(fullRequest))
|
||||
err := syncHandler.HandleMessage(ctx, senderId, msg)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("head update empty equal heads", func(t *testing.T) {
|
||||
treeId := "treeId"
|
||||
senderId := "senderId"
|
||||
chWithId := &treechangeproto.RawTreeChangeWithId{}
|
||||
headUpdate := &spacesyncproto.ObjectHeadUpdate{
|
||||
Heads: []string{"h1"},
|
||||
Changes: nil,
|
||||
SnapshotPath: []string{"h1"},
|
||||
}
|
||||
msg := spacesyncproto.WrapHeadUpdate(headUpdate, chWithId, treeId, "")
|
||||
cacheMock.EXPECT().
|
||||
GetTree(gomock.Any(), spaceId, treeId).
|
||||
Return(cache.TreeResult{
|
||||
Release: func() {},
|
||||
TreeContainer: treeContainer{objectTreeMock},
|
||||
}, nil)
|
||||
|
||||
objectTreeMock.EXPECT().
|
||||
Heads().
|
||||
Return([]string{"h1"})
|
||||
|
||||
err := syncHandler.HandleMessage(ctx, senderId, msg)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSyncHandler_HandleFullSyncRequest(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
ctx := context.Background()
|
||||
spaceId := "spaceId"
|
||||
cacheMock := mock_cache.NewMockTreeCache(ctrl)
|
||||
syncClientMock := mock_syncservice.NewMockSyncClient(ctrl)
|
||||
objectTreeMock := newTestObjMock(mock_tree.NewMockObjectTree(ctrl))
|
||||
|
||||
syncHandler := newSyncHandler(spaceId, cacheMock, syncClientMock)
|
||||
t.Run("full sync request with change", func(t *testing.T) {
|
||||
treeId := "treeId"
|
||||
senderId := "senderId"
|
||||
chWithId := &treechangeproto.RawTreeChangeWithId{}
|
||||
msg := spacesyncproto.WrapFullRequest(&spacesyncproto.ObjectFullSyncRequest{
|
||||
Heads: []string{"h1"},
|
||||
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
|
||||
SnapshotPath: []string{"h1"},
|
||||
}, chWithId, treeId, "")
|
||||
fullRequest := &spacesyncproto.ObjectSyncMessage{}
|
||||
|
||||
cacheMock.EXPECT().
|
||||
GetTree(gomock.Any(), spaceId, treeId).
|
||||
Return(cache.TreeResult{
|
||||
Release: func() {},
|
||||
TreeContainer: treeContainer{objectTreeMock},
|
||||
}, nil)
|
||||
objectTreeMock.EXPECT().
|
||||
Heads().
|
||||
Return([]string{"h2"})
|
||||
objectTreeMock.EXPECT().
|
||||
HasChanges(gomock.Eq([]string{"h1"})).
|
||||
Return(false)
|
||||
objectTreeMock.EXPECT().
|
||||
AddRawChanges(gomock.Any(), gomock.Eq([]*treechangeproto.RawTreeChangeWithId{chWithId})).
|
||||
Return(tree.AddResult{}, nil)
|
||||
syncClientMock.EXPECT().
|
||||
CreateFullSyncResponse(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"}), gomock.Eq("")).
|
||||
Return(fullRequest, nil)
|
||||
|
||||
syncClientMock.EXPECT().SendAsync(gomock.Eq([]string{senderId}), gomock.Eq(fullRequest))
|
||||
err := syncHandler.HandleMessage(ctx, senderId, msg)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("full sync request with change same heads", func(t *testing.T) {
|
||||
treeId := "treeId"
|
||||
senderId := "senderId"
|
||||
chWithId := &treechangeproto.RawTreeChangeWithId{}
|
||||
msg := spacesyncproto.WrapFullRequest(&spacesyncproto.ObjectFullSyncRequest{
|
||||
Heads: []string{"h2"},
|
||||
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
|
||||
SnapshotPath: []string{"h2"},
|
||||
}, chWithId, treeId, "")
|
||||
fullRequest := &spacesyncproto.ObjectSyncMessage{}
|
||||
|
||||
cacheMock.EXPECT().
|
||||
GetTree(gomock.Any(), spaceId, treeId).
|
||||
Return(cache.TreeResult{
|
||||
Release: func() {},
|
||||
TreeContainer: treeContainer{objectTreeMock},
|
||||
}, nil)
|
||||
objectTreeMock.EXPECT().
|
||||
Heads().
|
||||
Return([]string{"h2"})
|
||||
syncClientMock.EXPECT().
|
||||
CreateFullSyncResponse(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h2"}), gomock.Eq([]string{"h2"}), gomock.Eq("")).
|
||||
Return(fullRequest, nil)
|
||||
|
||||
syncClientMock.EXPECT().SendAsync(gomock.Eq([]string{senderId}), gomock.Eq(fullRequest))
|
||||
err := syncHandler.HandleMessage(ctx, senderId, msg)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("full sync request without change", func(t *testing.T) {
|
||||
treeId := "treeId"
|
||||
senderId := "senderId"
|
||||
chWithId := &treechangeproto.RawTreeChangeWithId{}
|
||||
msg := spacesyncproto.WrapFullRequest(&spacesyncproto.ObjectFullSyncRequest{
|
||||
Heads: []string{"h1"},
|
||||
SnapshotPath: []string{"h1"},
|
||||
}, chWithId, treeId, "")
|
||||
fullRequest := &spacesyncproto.ObjectSyncMessage{}
|
||||
|
||||
cacheMock.EXPECT().
|
||||
GetTree(gomock.Any(), spaceId, treeId).
|
||||
Return(cache.TreeResult{
|
||||
Release: func() {},
|
||||
TreeContainer: treeContainer{objectTreeMock},
|
||||
}, nil)
|
||||
syncClientMock.EXPECT().
|
||||
CreateFullSyncResponse(gomock.Eq(objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"}), gomock.Eq("")).
|
||||
Return(fullRequest, nil)
|
||||
|
||||
syncClientMock.EXPECT().SendAsync(gomock.Eq([]string{senderId}), gomock.Eq(fullRequest))
|
||||
err := syncHandler.HandleMessage(ctx, senderId, msg)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("full sync request with get tree error", func(t *testing.T) {
|
||||
treeId := "treeId"
|
||||
senderId := "senderId"
|
||||
chWithId := &treechangeproto.RawTreeChangeWithId{}
|
||||
msg := spacesyncproto.WrapFullRequest(&spacesyncproto.ObjectFullSyncRequest{
|
||||
Heads: []string{"h1"},
|
||||
SnapshotPath: []string{"h1"},
|
||||
}, chWithId, treeId, "")
|
||||
|
||||
cacheMock.EXPECT().
|
||||
GetTree(gomock.Any(), spaceId, treeId).
|
||||
Return(cache.TreeResult{}, fmt.Errorf("some"))
|
||||
|
||||
syncClientMock.EXPECT().
|
||||
SendAsync(gomock.Eq([]string{senderId}), gomock.Any())
|
||||
err := syncHandler.HandleMessage(ctx, senderId, msg)
|
||||
require.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSyncHandler_HandleFullSyncResponse(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
ctx := context.Background()
|
||||
spaceId := "spaceId"
|
||||
cacheMock := mock_cache.NewMockTreeCache(ctrl)
|
||||
syncClientMock := mock_syncservice.NewMockSyncClient(ctrl)
|
||||
objectTreeMock := newTestObjMock(mock_tree.NewMockObjectTree(ctrl))
|
||||
|
||||
syncHandler := newSyncHandler(spaceId, cacheMock, syncClientMock)
|
||||
t.Run("full sync response with change", func(t *testing.T) {
|
||||
treeId := "treeId"
|
||||
senderId := "senderId"
|
||||
chWithId := &treechangeproto.RawTreeChangeWithId{}
|
||||
msg := spacesyncproto.WrapFullResponse(&spacesyncproto.ObjectFullSyncResponse{
|
||||
Heads: []string{"h1"},
|
||||
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
|
||||
SnapshotPath: []string{"h1"},
|
||||
}, chWithId, treeId, "")
|
||||
|
||||
cacheMock.EXPECT().
|
||||
GetTree(gomock.Any(), spaceId, treeId).
|
||||
Return(cache.TreeResult{
|
||||
Release: func() {},
|
||||
TreeContainer: treeContainer{objectTreeMock},
|
||||
}, nil)
|
||||
objectTreeMock.EXPECT().
|
||||
Heads().
|
||||
Return([]string{"h2"})
|
||||
objectTreeMock.EXPECT().
|
||||
HasChanges(gomock.Eq([]string{"h1"})).
|
||||
Return(false)
|
||||
objectTreeMock.EXPECT().
|
||||
AddRawChanges(gomock.Any(), gomock.Eq([]*treechangeproto.RawTreeChangeWithId{chWithId})).
|
||||
Return(tree.AddResult{}, nil)
|
||||
|
||||
err := syncHandler.HandleMessage(ctx, senderId, msg)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("full sync response same heads", func(t *testing.T) {
|
||||
treeId := "treeId"
|
||||
senderId := "senderId"
|
||||
chWithId := &treechangeproto.RawTreeChangeWithId{}
|
||||
msg := spacesyncproto.WrapFullResponse(&spacesyncproto.ObjectFullSyncResponse{
|
||||
Heads: []string{"h1"},
|
||||
Changes: []*treechangeproto.RawTreeChangeWithId{chWithId},
|
||||
SnapshotPath: []string{"h1"},
|
||||
}, chWithId, treeId, "")
|
||||
|
||||
cacheMock.EXPECT().
|
||||
GetTree(gomock.Any(), spaceId, treeId).
|
||||
Return(cache.TreeResult{
|
||||
Release: func() {},
|
||||
TreeContainer: treeContainer{objectTreeMock},
|
||||
}, nil)
|
||||
objectTreeMock.EXPECT().
|
||||
Heads().
|
||||
Return([]string{"h1"})
|
||||
|
||||
err := syncHandler.HandleMessage(ctx, senderId, msg)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
//go:generate mockgen -destination mock_syncservice/mock_syncservice.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice SyncClient
|
||||
package syncservice
|
||||
|
||||
import (
|
||||
@ -7,19 +8,13 @@ import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/rpc/rpcerr"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto"
|
||||
"time"
|
||||
)
|
||||
|
||||
var log = logger.NewNamed("syncservice").Sugar()
|
||||
|
||||
type SyncService interface {
|
||||
NotifyHeadUpdate(
|
||||
ctx context.Context,
|
||||
treeId string,
|
||||
root *treechangeproto.RawTreeChangeWithId,
|
||||
update *spacesyncproto.ObjectHeadUpdate) (err error)
|
||||
StreamPool() StreamPool
|
||||
SyncClient() SyncClient
|
||||
|
||||
Init()
|
||||
Close() (err error)
|
||||
@ -34,36 +29,44 @@ const respPeersStreamCheckInterval = time.Second * 10
|
||||
type syncService struct {
|
||||
spaceId string
|
||||
|
||||
syncHandler SyncHandler
|
||||
streamPool StreamPool
|
||||
headNotifiable HeadNotifiable
|
||||
configuration nodeconf.Configuration
|
||||
syncClient SyncClient
|
||||
clientFactory spacesyncproto.ClientFactory
|
||||
|
||||
streamLoopCtx context.Context
|
||||
stopStreamLoop context.CancelFunc
|
||||
connector nodeconf.ConfConnector
|
||||
streamLoopDone chan struct{}
|
||||
}
|
||||
|
||||
func NewSyncService(spaceId string, headNotifiable HeadNotifiable, cache cache.TreeCache, configuration nodeconf.Configuration) SyncService {
|
||||
func NewSyncService(
|
||||
spaceId string,
|
||||
headNotifiable HeadNotifiable,
|
||||
cache cache.TreeCache,
|
||||
configuration nodeconf.Configuration,
|
||||
confConnector nodeconf.ConfConnector) SyncService {
|
||||
var syncHandler SyncHandler
|
||||
streamPool := newStreamPool(func(ctx context.Context, senderId string, message *spacesyncproto.ObjectSyncMessage) (err error) {
|
||||
return syncHandler.HandleMessage(ctx, senderId, message)
|
||||
})
|
||||
syncHandler = newSyncHandler(spaceId, cache, streamPool)
|
||||
return newSyncService(spaceId, headNotifiable, syncHandler, streamPool, configuration)
|
||||
factory := newRequestFactory()
|
||||
syncClient := newSyncClient(spaceId, streamPool, headNotifiable, factory, configuration)
|
||||
syncHandler = newSyncHandler(spaceId, cache, syncClient)
|
||||
return newSyncService(
|
||||
spaceId,
|
||||
syncClient,
|
||||
spacesyncproto.ClientFactoryFunc(spacesyncproto.NewDRPCSpaceClient),
|
||||
confConnector)
|
||||
}
|
||||
|
||||
func newSyncService(
|
||||
spaceId string,
|
||||
headNotifiable HeadNotifiable,
|
||||
syncHandler SyncHandler,
|
||||
streamPool StreamPool,
|
||||
configuration nodeconf.Configuration) *syncService {
|
||||
syncClient SyncClient,
|
||||
clientFactory spacesyncproto.ClientFactory,
|
||||
connector nodeconf.ConfConnector) *syncService {
|
||||
return &syncService{
|
||||
syncHandler: syncHandler,
|
||||
streamPool: streamPool,
|
||||
headNotifiable: headNotifiable,
|
||||
configuration: configuration,
|
||||
syncClient: syncClient,
|
||||
connector: connector,
|
||||
clientFactory: clientFactory,
|
||||
spaceId: spaceId,
|
||||
streamLoopDone: make(chan struct{}),
|
||||
}
|
||||
@ -77,32 +80,24 @@ func (s *syncService) Init() {
|
||||
func (s *syncService) Close() (err error) {
|
||||
s.stopStreamLoop()
|
||||
<-s.streamLoopDone
|
||||
return s.streamPool.Close()
|
||||
}
|
||||
|
||||
func (s *syncService) NotifyHeadUpdate(
|
||||
ctx context.Context,
|
||||
treeId string,
|
||||
header *treechangeproto.RawTreeChangeWithId,
|
||||
update *spacesyncproto.ObjectHeadUpdate) (err error) {
|
||||
s.headNotifiable.UpdateHeads(treeId, update.Heads)
|
||||
return s.streamPool.BroadcastAsync(spacesyncproto.WrapHeadUpdate(update, header, treeId, ""))
|
||||
return s.syncClient.Close()
|
||||
}
|
||||
|
||||
func (s *syncService) responsibleStreamCheckLoop(ctx context.Context) {
|
||||
defer close(s.streamLoopDone)
|
||||
checkResponsiblePeers := func() {
|
||||
respPeers, err := s.configuration.ResponsiblePeers(ctx, s.spaceId)
|
||||
respPeers, err := s.connector.DialResponsiblePeers(ctx, s.spaceId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, peer := range respPeers {
|
||||
if s.streamPool.HasActiveStream(peer.Id()) {
|
||||
if s.syncClient.HasActiveStream(peer.Id()) {
|
||||
continue
|
||||
}
|
||||
cl := spacesyncproto.NewDRPCSpaceClient(peer)
|
||||
stream, err := cl.Stream(ctx)
|
||||
stream, err := s.clientFactory.Client(peer).Stream(ctx)
|
||||
if err != nil {
|
||||
err = rpcerr.Unwrap(err)
|
||||
log.With("spaceId", s.spaceId).Errorf("failed to open stream: %v", err)
|
||||
// so here probably the request is failed because there is no such space,
|
||||
// but diffService should handle such cases by sending pushSpace
|
||||
continue
|
||||
@ -111,10 +106,10 @@ func (s *syncService) responsibleStreamCheckLoop(ctx context.Context) {
|
||||
err = stream.Send(&spacesyncproto.ObjectSyncMessage{SpaceId: s.spaceId})
|
||||
if err != nil {
|
||||
err = rpcerr.Unwrap(err)
|
||||
log.With("spaceId", s.spaceId).Errorf("failed to open stream: %v", err)
|
||||
log.With("spaceId", s.spaceId).Errorf("failed to send first message to stream: %v", err)
|
||||
continue
|
||||
}
|
||||
s.streamPool.AddAndReadStreamAsync(stream)
|
||||
s.syncClient.AddAndReadStreamAsync(stream)
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,6 +126,6 @@ func (s *syncService) responsibleStreamCheckLoop(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *syncService) StreamPool() StreamPool {
|
||||
return s.streamPool
|
||||
func (s *syncService) SyncClient() SyncClient {
|
||||
return s.syncClient
|
||||
}
|
||||
|
||||
@ -2,7 +2,6 @@ package synctree
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list"
|
||||
@ -14,105 +13,101 @@ import (
|
||||
// SyncTree sends head updates to sync service and also sends new changes to update listener
|
||||
type SyncTree struct {
|
||||
tree.ObjectTree
|
||||
syncService syncservice.SyncService
|
||||
listener updatelistener.UpdateListener
|
||||
syncClient syncservice.SyncClient
|
||||
listener updatelistener.UpdateListener
|
||||
}
|
||||
|
||||
var createDerivedObjectTree = tree.CreateDerivedObjectTree
|
||||
var createObjectTree = tree.CreateObjectTree
|
||||
var buildObjectTree = tree.BuildObjectTree
|
||||
|
||||
func DeriveSyncTree(
|
||||
ctx context.Context,
|
||||
payload tree.ObjectTreeCreatePayload,
|
||||
syncService syncservice.SyncService,
|
||||
syncClient syncservice.SyncClient,
|
||||
listener updatelistener.UpdateListener,
|
||||
aclList list.ACLList,
|
||||
createStorage storage.TreeStorageCreatorFunc) (t tree.ObjectTree, err error) {
|
||||
t, err = tree.CreateDerivedObjectTree(payload, aclList, createStorage)
|
||||
t, err = createDerivedObjectTree(payload, aclList, createStorage)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
t = &SyncTree{
|
||||
ObjectTree: t,
|
||||
syncService: syncService,
|
||||
listener: listener,
|
||||
ObjectTree: t,
|
||||
syncClient: syncClient,
|
||||
listener: listener,
|
||||
}
|
||||
|
||||
err = syncService.NotifyHeadUpdate(ctx, t.ID(), t.Header(), &spacesyncproto.ObjectHeadUpdate{
|
||||
Heads: t.Heads(),
|
||||
SnapshotPath: t.SnapshotPath(),
|
||||
})
|
||||
headUpdate := syncClient.CreateHeadUpdate(t, nil)
|
||||
err = syncClient.BroadcastAsync(headUpdate)
|
||||
return
|
||||
}
|
||||
|
||||
func CreateSyncTree(
|
||||
ctx context.Context,
|
||||
payload tree.ObjectTreeCreatePayload,
|
||||
syncService syncservice.SyncService,
|
||||
syncClient syncservice.SyncClient,
|
||||
listener updatelistener.UpdateListener,
|
||||
aclList list.ACLList,
|
||||
createStorage storage.TreeStorageCreatorFunc) (t tree.ObjectTree, err error) {
|
||||
t, err = tree.CreateObjectTree(payload, aclList, createStorage)
|
||||
t, err = createObjectTree(payload, aclList, createStorage)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
t = &SyncTree{
|
||||
ObjectTree: t,
|
||||
syncService: syncService,
|
||||
listener: listener,
|
||||
ObjectTree: t,
|
||||
syncClient: syncClient,
|
||||
listener: listener,
|
||||
}
|
||||
|
||||
err = syncService.NotifyHeadUpdate(ctx, t.ID(), t.Header(), &spacesyncproto.ObjectHeadUpdate{
|
||||
Heads: t.Heads(),
|
||||
SnapshotPath: t.SnapshotPath(),
|
||||
})
|
||||
headUpdate := syncClient.CreateHeadUpdate(t, nil)
|
||||
err = syncClient.BroadcastAsync(headUpdate)
|
||||
return
|
||||
}
|
||||
|
||||
func BuildSyncTree(
|
||||
ctx context.Context,
|
||||
syncService syncservice.SyncService,
|
||||
syncClient syncservice.SyncClient,
|
||||
treeStorage storage.TreeStorage,
|
||||
listener updatelistener.UpdateListener,
|
||||
aclList list.ACLList) (t tree.ObjectTree, err error) {
|
||||
return buildSyncTree(ctx, syncService, treeStorage, listener, aclList)
|
||||
return buildSyncTree(ctx, syncClient, treeStorage, listener, aclList)
|
||||
}
|
||||
|
||||
func buildSyncTree(
|
||||
ctx context.Context,
|
||||
syncService syncservice.SyncService,
|
||||
syncClient syncservice.SyncClient,
|
||||
treeStorage storage.TreeStorage,
|
||||
listener updatelistener.UpdateListener,
|
||||
aclList list.ACLList) (t tree.ObjectTree, err error) {
|
||||
t, err = tree.BuildObjectTree(treeStorage, aclList)
|
||||
t, err = buildObjectTree(treeStorage, aclList)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
t = &SyncTree{
|
||||
ObjectTree: t,
|
||||
syncService: syncService,
|
||||
listener: listener,
|
||||
ObjectTree: t,
|
||||
syncClient: syncClient,
|
||||
listener: listener,
|
||||
}
|
||||
|
||||
err = syncService.NotifyHeadUpdate(ctx, t.ID(), t.Header(), &spacesyncproto.ObjectHeadUpdate{
|
||||
Heads: t.Heads(),
|
||||
SnapshotPath: t.SnapshotPath(),
|
||||
})
|
||||
headUpdate := syncClient.CreateHeadUpdate(t, nil)
|
||||
// here we will have different behaviour based on who is sending this update
|
||||
err = syncClient.BroadcastAsyncOrSendResponsible(headUpdate)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *SyncTree) AddContent(ctx context.Context, content tree.SignableChangeContent) (res tree.AddResult, err error) {
|
||||
res, err = s.AddContent(ctx, content)
|
||||
res, err = s.ObjectTree.AddContent(ctx, content)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = s.syncService.NotifyHeadUpdate(ctx, s.ID(), s.Header(), &spacesyncproto.ObjectHeadUpdate{
|
||||
Heads: res.Heads,
|
||||
Changes: res.Added,
|
||||
SnapshotPath: s.SnapshotPath(),
|
||||
})
|
||||
headUpdate := s.syncClient.CreateHeadUpdate(s, res.Added)
|
||||
err = s.syncClient.BroadcastAsync(headUpdate)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *SyncTree) AddRawChanges(ctx context.Context, changes ...*treechangeproto.RawTreeChangeWithId) (res tree.AddResult, err error) {
|
||||
res, err = s.AddRawChanges(ctx, changes...)
|
||||
res, err = s.ObjectTree.AddRawChanges(ctx, changes...)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -125,11 +120,8 @@ func (s *SyncTree) AddRawChanges(ctx context.Context, changes ...*treechangeprot
|
||||
s.listener.Rebuild(s)
|
||||
}
|
||||
|
||||
err = s.syncService.NotifyHeadUpdate(ctx, s.ID(), s.Header(), &spacesyncproto.ObjectHeadUpdate{
|
||||
Heads: res.Heads,
|
||||
Changes: res.Added,
|
||||
SnapshotPath: s.SnapshotPath(),
|
||||
})
|
||||
headUpdate := s.syncClient.CreateHeadUpdate(s, res.Added)
|
||||
err = s.syncClient.BroadcastAsync(headUpdate)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
176
common/commonspace/synctree/synctree_test.go
Normal file
176
common/commonspace/synctree/synctree_test.go
Normal file
@ -0,0 +1,176 @@
|
||||
package synctree
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice/mock_syncservice"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener/mock_updatelistener"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list/mock_list"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage/mock_storage"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree"
|
||||
mock_tree "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree/mock_objecttree"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type syncTreeMatcher struct {
|
||||
objTree tree.ObjectTree
|
||||
client syncservice.SyncClient
|
||||
listener updatelistener.UpdateListener
|
||||
}
|
||||
|
||||
func (s syncTreeMatcher) Matches(x interface{}) bool {
|
||||
t, ok := x.(*SyncTree)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return s.objTree == t.ObjectTree && t.syncClient == s.client && t.listener == s.listener
|
||||
}
|
||||
|
||||
func (s syncTreeMatcher) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func Test_DeriveSyncTree(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
updateListenerMock := mock_updatelistener.NewMockUpdateListener(ctrl)
|
||||
syncClientMock := mock_syncservice.NewMockSyncClient(ctrl)
|
||||
aclListMock := mock_list.NewMockACLList(ctrl)
|
||||
createStorage := storage.TreeStorageCreatorFunc(func(payload storage.TreeStorageCreatePayload) (storage.TreeStorage, error) {
|
||||
return nil, nil
|
||||
})
|
||||
objTreeMock := mock_tree.NewMockObjectTree(ctrl)
|
||||
createDerivedObjectTree = func(payload tree.ObjectTreeCreatePayload, l list.ACLList, create storage.TreeStorageCreatorFunc) (objTree tree.ObjectTree, err error) {
|
||||
require.Equal(t, l, aclListMock)
|
||||
return objTreeMock, nil
|
||||
}
|
||||
headUpdate := &spacesyncproto.ObjectSyncMessage{}
|
||||
syncClientMock.EXPECT().CreateHeadUpdate(syncTreeMatcher{objTreeMock, syncClientMock, updateListenerMock}, gomock.Nil()).Return(headUpdate)
|
||||
syncClientMock.EXPECT().BroadcastAsync(gomock.Eq(headUpdate)).Return(nil)
|
||||
|
||||
_, err := DeriveSyncTree(ctx, tree.ObjectTreeCreatePayload{}, syncClientMock, updateListenerMock, aclListMock, createStorage)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func Test_CreateSyncTree(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
updateListenerMock := mock_updatelistener.NewMockUpdateListener(ctrl)
|
||||
syncClientMock := mock_syncservice.NewMockSyncClient(ctrl)
|
||||
aclListMock := mock_list.NewMockACLList(ctrl)
|
||||
createStorage := storage.TreeStorageCreatorFunc(func(payload storage.TreeStorageCreatePayload) (storage.TreeStorage, error) {
|
||||
return nil, nil
|
||||
})
|
||||
objTreeMock := mock_tree.NewMockObjectTree(ctrl)
|
||||
createObjectTree = func(payload tree.ObjectTreeCreatePayload, l list.ACLList, create storage.TreeStorageCreatorFunc) (objTree tree.ObjectTree, err error) {
|
||||
require.Equal(t, l, aclListMock)
|
||||
return objTreeMock, nil
|
||||
}
|
||||
headUpdate := &spacesyncproto.ObjectSyncMessage{}
|
||||
syncClientMock.EXPECT().CreateHeadUpdate(syncTreeMatcher{objTreeMock, syncClientMock, updateListenerMock}, gomock.Nil()).Return(headUpdate)
|
||||
syncClientMock.EXPECT().BroadcastAsync(gomock.Eq(headUpdate)).Return(nil)
|
||||
|
||||
_, err := CreateSyncTree(ctx, tree.ObjectTreeCreatePayload{}, syncClientMock, updateListenerMock, aclListMock, createStorage)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func Test_BuildSyncTree(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
updateListenerMock := mock_updatelistener.NewMockUpdateListener(ctrl)
|
||||
syncClientMock := mock_syncservice.NewMockSyncClient(ctrl)
|
||||
aclListMock := mock_list.NewMockACLList(ctrl)
|
||||
storageMock := mock_storage.NewMockTreeStorage(ctrl)
|
||||
objTreeMock := mock_tree.NewMockObjectTree(ctrl)
|
||||
buildObjectTree = func(store storage.TreeStorage, l list.ACLList) (objTree tree.ObjectTree, err error) {
|
||||
require.Equal(t, aclListMock, l)
|
||||
require.Equal(t, store, storageMock)
|
||||
return objTreeMock, nil
|
||||
}
|
||||
headUpdate := &spacesyncproto.ObjectSyncMessage{}
|
||||
syncClientMock.EXPECT().CreateHeadUpdate(syncTreeMatcher{objTreeMock, syncClientMock, updateListenerMock}, gomock.Nil()).Return(headUpdate)
|
||||
syncClientMock.EXPECT().BroadcastAsyncOrSendResponsible(gomock.Eq(headUpdate)).Return(nil)
|
||||
|
||||
tr, err := BuildSyncTree(ctx, syncClientMock, storageMock, updateListenerMock, aclListMock)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("AddRawChanges update", func(t *testing.T) {
|
||||
changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}}
|
||||
expectedRes := tree.AddResult{
|
||||
Added: changes,
|
||||
Mode: tree.Append,
|
||||
}
|
||||
objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(changes)).
|
||||
Return(expectedRes, nil)
|
||||
updateListenerMock.EXPECT().Update(tr)
|
||||
|
||||
syncClientMock.EXPECT().CreateHeadUpdate(gomock.Eq(tr), gomock.Eq(changes)).Return(headUpdate)
|
||||
syncClientMock.EXPECT().BroadcastAsync(gomock.Eq(headUpdate)).Return(nil)
|
||||
res, err := tr.AddRawChanges(ctx, changes...)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectedRes, res)
|
||||
})
|
||||
|
||||
t.Run("AddRawChanges rebuild", func(t *testing.T) {
|
||||
changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}}
|
||||
expectedRes := tree.AddResult{
|
||||
Added: changes,
|
||||
Mode: tree.Rebuild,
|
||||
}
|
||||
objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(changes)).
|
||||
Return(expectedRes, nil)
|
||||
updateListenerMock.EXPECT().Rebuild(tr)
|
||||
|
||||
syncClientMock.EXPECT().CreateHeadUpdate(gomock.Eq(tr), gomock.Eq(changes)).Return(headUpdate)
|
||||
syncClientMock.EXPECT().BroadcastAsync(gomock.Eq(headUpdate)).Return(nil)
|
||||
res, err := tr.AddRawChanges(ctx, changes...)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectedRes, res)
|
||||
})
|
||||
|
||||
t.Run("AddRawChanges nothing", func(t *testing.T) {
|
||||
changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}}
|
||||
expectedRes := tree.AddResult{
|
||||
Added: changes,
|
||||
Mode: tree.Nothing,
|
||||
}
|
||||
objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(changes)).
|
||||
Return(expectedRes, nil)
|
||||
|
||||
res, err := tr.AddRawChanges(ctx, changes...)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectedRes, res)
|
||||
})
|
||||
|
||||
t.Run("AddContent", func(t *testing.T) {
|
||||
changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}}
|
||||
content := tree.SignableChangeContent{
|
||||
Data: []byte("abcde"),
|
||||
}
|
||||
expectedRes := tree.AddResult{
|
||||
Mode: tree.Append,
|
||||
Added: changes,
|
||||
}
|
||||
objTreeMock.EXPECT().AddContent(gomock.Any(), gomock.Eq(content)).
|
||||
Return(expectedRes, nil)
|
||||
|
||||
syncClientMock.EXPECT().CreateHeadUpdate(gomock.Eq(tr), gomock.Eq(changes)).Return(headUpdate)
|
||||
syncClientMock.EXPECT().BroadcastAsync(gomock.Eq(headUpdate)).Return(nil)
|
||||
res, err := tr.AddContent(ctx, content)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectedRes, res)
|
||||
})
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener (interfaces: UpdateListener)
|
||||
|
||||
// Package mock_updatelistener is a generated GoMock package.
|
||||
package mock_updatelistener
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
tree "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockUpdateListener is a mock of UpdateListener interface.
|
||||
type MockUpdateListener struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockUpdateListenerMockRecorder
|
||||
}
|
||||
|
||||
// MockUpdateListenerMockRecorder is the mock recorder for MockUpdateListener.
|
||||
type MockUpdateListenerMockRecorder struct {
|
||||
mock *MockUpdateListener
|
||||
}
|
||||
|
||||
// NewMockUpdateListener creates a new mock instance.
|
||||
func NewMockUpdateListener(ctrl *gomock.Controller) *MockUpdateListener {
|
||||
mock := &MockUpdateListener{ctrl: ctrl}
|
||||
mock.recorder = &MockUpdateListenerMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockUpdateListener) EXPECT() *MockUpdateListenerMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Rebuild mocks base method.
|
||||
func (m *MockUpdateListener) Rebuild(arg0 tree.ObjectTree) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "Rebuild", arg0)
|
||||
}
|
||||
|
||||
// Rebuild indicates an expected call of Rebuild.
|
||||
func (mr *MockUpdateListenerMockRecorder) Rebuild(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Rebuild", reflect.TypeOf((*MockUpdateListener)(nil).Rebuild), arg0)
|
||||
}
|
||||
|
||||
// Update mocks base method.
|
||||
func (m *MockUpdateListener) Update(arg0 tree.ObjectTree) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "Update", arg0)
|
||||
}
|
||||
|
||||
// Update indicates an expected call of Update.
|
||||
func (mr *MockUpdateListenerMockRecorder) Update(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockUpdateListener)(nil).Update), arg0)
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
//go:generate mockgen -destination mock_updatelistener/mock_updatelistener.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener UpdateListener
|
||||
package updatelistener
|
||||
|
||||
import "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree"
|
||||
|
||||
54
common/nodeconf/confconnector.go
Normal file
54
common/nodeconf/confconnector.go
Normal file
@ -0,0 +1,54 @@
|
||||
package nodeconf
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/pool"
|
||||
)
|
||||
|
||||
type ConfConnector interface {
|
||||
GetResponsiblePeers(ctx context.Context, spaceId string) ([]peer.Peer, error)
|
||||
DialResponsiblePeers(ctx context.Context, spaceId string) ([]peer.Peer, error)
|
||||
}
|
||||
|
||||
type confConnector struct {
|
||||
conf Configuration
|
||||
pool pool.Pool
|
||||
}
|
||||
|
||||
func NewConfConnector(conf Configuration, pool pool.Pool) ConfConnector {
|
||||
return &confConnector{conf: conf, pool: pool}
|
||||
}
|
||||
|
||||
func (s *confConnector) GetResponsiblePeers(ctx context.Context, spaceId string) ([]peer.Peer, error) {
|
||||
return s.dialOrConnect(ctx, spaceId, s.pool.Get, s.pool.GetOneOf)
|
||||
}
|
||||
|
||||
func (s *confConnector) DialResponsiblePeers(ctx context.Context, spaceId string) ([]peer.Peer, error) {
|
||||
return s.dialOrConnect(ctx, spaceId, s.pool.Dial, s.pool.DialOneOf)
|
||||
}
|
||||
|
||||
func (s *confConnector) dialOrConnect(
|
||||
ctx context.Context, spaceId string,
|
||||
connectOne func(context.Context, string) (peer.Peer, error),
|
||||
connectOneOf func(context.Context, []string) (peer.Peer, error)) (peers []peer.Peer, err error) {
|
||||
allNodes := s.conf.NodeIds(spaceId)
|
||||
if !s.conf.IsResponsible(spaceId) {
|
||||
for _, id := range allNodes {
|
||||
var p peer.Peer
|
||||
p, err = connectOne(ctx, id)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
peers = append(peers, p)
|
||||
}
|
||||
} else {
|
||||
var p peer.Peer
|
||||
p, err = connectOneOf(ctx, allNodes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
peers = []peer.Peer{p}
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -1,10 +1,7 @@
|
||||
//go:generate mockgen -destination mock_nodeconf/mock_nodeconf.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf Configuration,ConfConnector
|
||||
package nodeconf
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/pool"
|
||||
"github.com/anytypeio/go-chash"
|
||||
)
|
||||
|
||||
@ -15,12 +12,6 @@ func New() Service {
|
||||
type Configuration interface {
|
||||
// Id returns current nodeconf id
|
||||
Id() string
|
||||
// AllPeers returns all peers by spaceId except current account
|
||||
AllPeers(ctx context.Context, spaceId string) (peers []peer.Peer, err error)
|
||||
// OnePeer returns one of peer for spaceId
|
||||
OnePeer(ctx context.Context, spaceId string) (p peer.Peer, err error)
|
||||
// ResponsiblePeers returns peers for the space id that are responsible for the space
|
||||
ResponsiblePeers(ctx context.Context, spaceId string) (peers []peer.Peer, err error)
|
||||
// NodeIds returns list of peerId for given spaceId
|
||||
NodeIds(spaceId string) []string
|
||||
// IsResponsible checks if current account responsible for given spaceId
|
||||
@ -30,7 +21,6 @@ type Configuration interface {
|
||||
type configuration struct {
|
||||
id string
|
||||
accountId string
|
||||
pool pool.Pool
|
||||
chash chash.CHash
|
||||
}
|
||||
|
||||
@ -38,40 +28,6 @@ func (c *configuration) Id() string {
|
||||
return c.id
|
||||
}
|
||||
|
||||
func (c *configuration) AllPeers(ctx context.Context, spaceId string) (peers []peer.Peer, err error) {
|
||||
nodeIds := c.NodeIds(spaceId)
|
||||
peers = make([]peer.Peer, 0, len(nodeIds))
|
||||
for _, id := range nodeIds {
|
||||
p, e := c.pool.Get(ctx, id)
|
||||
if e == nil {
|
||||
peers = append(peers, p)
|
||||
}
|
||||
}
|
||||
if len(peers) == 0 {
|
||||
return nil, fmt.Errorf("unable to connect to any node")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c *configuration) ResponsiblePeers(ctx context.Context, spaceId string) (peers []peer.Peer, err error) {
|
||||
if c.IsResponsible(spaceId) {
|
||||
return c.AllPeers(ctx, spaceId)
|
||||
} else {
|
||||
var one peer.Peer
|
||||
one, err = c.OnePeer(ctx, spaceId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
peers = []peer.Peer{one}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (c *configuration) OnePeer(ctx context.Context, spaceId string) (p peer.Peer, err error) {
|
||||
nodeIds := c.NodeIds(spaceId)
|
||||
return c.pool.GetOneOf(ctx, nodeIds)
|
||||
}
|
||||
|
||||
func (c *configuration) NodeIds(spaceId string) []string {
|
||||
members := c.chash.GetMembers(spaceId)
|
||||
res := make([]string, 0, len(members))
|
||||
|
||||
131
common/nodeconf/mock_nodeconf/mock_nodeconf.go
Normal file
131
common/nodeconf/mock_nodeconf/mock_nodeconf.go
Normal file
@ -0,0 +1,131 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf (interfaces: Configuration,ConfConnector)
|
||||
|
||||
// Package mock_nodeconf is a generated GoMock package.
|
||||
package mock_nodeconf
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
peer "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockConfiguration is a mock of Configuration interface.
|
||||
type MockConfiguration struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockConfigurationMockRecorder
|
||||
}
|
||||
|
||||
// MockConfigurationMockRecorder is the mock recorder for MockConfiguration.
|
||||
type MockConfigurationMockRecorder struct {
|
||||
mock *MockConfiguration
|
||||
}
|
||||
|
||||
// NewMockConfiguration creates a new mock instance.
|
||||
func NewMockConfiguration(ctrl *gomock.Controller) *MockConfiguration {
|
||||
mock := &MockConfiguration{ctrl: ctrl}
|
||||
mock.recorder = &MockConfigurationMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockConfiguration) EXPECT() *MockConfigurationMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Id mocks base method.
|
||||
func (m *MockConfiguration) Id() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Id")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Id indicates an expected call of Id.
|
||||
func (mr *MockConfigurationMockRecorder) Id() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Id", reflect.TypeOf((*MockConfiguration)(nil).Id))
|
||||
}
|
||||
|
||||
// IsResponsible mocks base method.
|
||||
func (m *MockConfiguration) IsResponsible(arg0 string) bool {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "IsResponsible", arg0)
|
||||
ret0, _ := ret[0].(bool)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// IsResponsible indicates an expected call of IsResponsible.
|
||||
func (mr *MockConfigurationMockRecorder) IsResponsible(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsResponsible", reflect.TypeOf((*MockConfiguration)(nil).IsResponsible), arg0)
|
||||
}
|
||||
|
||||
// NodeIds mocks base method.
|
||||
func (m *MockConfiguration) NodeIds(arg0 string) []string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "NodeIds", arg0)
|
||||
ret0, _ := ret[0].([]string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// NodeIds indicates an expected call of NodeIds.
|
||||
func (mr *MockConfigurationMockRecorder) NodeIds(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeIds", reflect.TypeOf((*MockConfiguration)(nil).NodeIds), arg0)
|
||||
}
|
||||
|
||||
// MockConfConnector is a mock of ConfConnector interface.
|
||||
type MockConfConnector struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockConfConnectorMockRecorder
|
||||
}
|
||||
|
||||
// MockConfConnectorMockRecorder is the mock recorder for MockConfConnector.
|
||||
type MockConfConnectorMockRecorder struct {
|
||||
mock *MockConfConnector
|
||||
}
|
||||
|
||||
// NewMockConfConnector creates a new mock instance.
|
||||
func NewMockConfConnector(ctrl *gomock.Controller) *MockConfConnector {
|
||||
mock := &MockConfConnector{ctrl: ctrl}
|
||||
mock.recorder = &MockConfConnectorMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockConfConnector) EXPECT() *MockConfConnectorMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// DialResponsiblePeers mocks base method.
|
||||
func (m *MockConfConnector) DialResponsiblePeers(arg0 context.Context, arg1 string) ([]peer.Peer, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DialResponsiblePeers", arg0, arg1)
|
||||
ret0, _ := ret[0].([]peer.Peer)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// DialResponsiblePeers indicates an expected call of DialResponsiblePeers.
|
||||
func (mr *MockConfConnectorMockRecorder) DialResponsiblePeers(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DialResponsiblePeers", reflect.TypeOf((*MockConfConnector)(nil).DialResponsiblePeers), arg0, arg1)
|
||||
}
|
||||
|
||||
// GetResponsiblePeers mocks base method.
|
||||
func (m *MockConfConnector) GetResponsiblePeers(arg0 context.Context, arg1 string) ([]peer.Peer, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetResponsiblePeers", arg0, arg1)
|
||||
ret0, _ := ret[0].([]peer.Peer)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetResponsiblePeers indicates an expected call of GetResponsiblePeers.
|
||||
func (mr *MockConfConnectorMockRecorder) GetResponsiblePeers(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetResponsiblePeers", reflect.TypeOf((*MockConfConnector)(nil).GetResponsiblePeers), arg0, arg1)
|
||||
}
|
||||
@ -3,7 +3,6 @@ package nodeconf
|
||||
import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/app"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/pool"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/config"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/encryptionkey"
|
||||
@ -29,7 +28,6 @@ type Service interface {
|
||||
|
||||
type service struct {
|
||||
accountId string
|
||||
pool pool.Pool
|
||||
|
||||
consensusPeers []string
|
||||
last Configuration
|
||||
@ -53,12 +51,10 @@ func (n *Node) Capacity() float64 {
|
||||
func (s *service) Init(a *app.App) (err error) {
|
||||
conf := a.MustComponent(config.CName).(*config.Config)
|
||||
s.accountId = conf.Account.PeerId
|
||||
s.pool = a.MustComponent(pool.CName).(pool.Pool)
|
||||
|
||||
config := &configuration{
|
||||
id: "config",
|
||||
accountId: s.accountId,
|
||||
pool: s.pool,
|
||||
}
|
||||
if config.chash, err = chash.New(chash.Config{
|
||||
PartitionCount: partitionCount,
|
||||
|
||||
@ -48,12 +48,16 @@ type service struct {
|
||||
|
||||
func (s *service) Init(a *app.App) (err error) {
|
||||
s.db = a.MustComponent(db.CName).(db.Service)
|
||||
s.cache = ocache.New(s.loadLog,
|
||||
|
||||
cacheOpts := []ocache.Option{
|
||||
ocache.WithTTL(cacheTTL),
|
||||
ocache.WithRefCounter(false),
|
||||
ocache.WithLogger(log.Named("cache").Sugar()),
|
||||
ocache.WithPrometheus(a.MustComponent(metric.CName).(metric.Metric).Registry(), "consensus", "logcache"),
|
||||
)
|
||||
}
|
||||
if ms := a.Component(metric.CName); ms != nil {
|
||||
cacheOpts = append(cacheOpts, ocache.WithPrometheus(ms.(metric.Metric).Registry(), "consensus", "logcache"))
|
||||
}
|
||||
s.cache = ocache.New(s.loadLog, cacheOpts...)
|
||||
|
||||
return s.db.SetChangeReceiver(s.receiveChange)
|
||||
}
|
||||
|
||||
9
go.mod
9
go.mod
@ -6,15 +6,19 @@ require (
|
||||
github.com/anytypeio/go-chash v0.0.0-20220629194632-4ad1154fe232
|
||||
github.com/awalterschulze/gographviz v0.0.0-20190522210029-fa59802746ab
|
||||
github.com/cespare/xxhash v1.1.0
|
||||
github.com/cheggaaa/mb/v2 v2.0.1
|
||||
github.com/goccy/go-graphviz v0.0.9
|
||||
github.com/gogo/protobuf v1.3.2
|
||||
github.com/golang/mock v1.6.0
|
||||
github.com/huandu/skiplist v1.2.0
|
||||
github.com/ipfs/go-cid v0.1.0
|
||||
github.com/libp2p/go-libp2p v0.20.3
|
||||
github.com/libp2p/go-libp2p-core v0.16.1
|
||||
github.com/minio/sha256-simd v1.0.0
|
||||
github.com/mr-tron/base58 v1.2.0
|
||||
github.com/multiformats/go-multibase v0.0.3
|
||||
github.com/multiformats/go-multihash v0.1.0
|
||||
github.com/prometheus/client_golang v1.13.0
|
||||
github.com/stretchr/testify v1.8.0
|
||||
github.com/zeebo/blake3 v0.2.3
|
||||
github.com/zeebo/errs v1.3.0
|
||||
@ -32,7 +36,6 @@ require (
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.1.3 // indirect
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/cheggaaa/mb/v2 v2.0.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
|
||||
github.com/fogleman/gg v1.3.0 // indirect
|
||||
@ -46,7 +49,6 @@ require (
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
|
||||
github.com/mr-tron/base58 v1.2.0 // indirect
|
||||
github.com/multiformats/go-base32 v0.0.3 // indirect
|
||||
github.com/multiformats/go-base36 v0.1.0 // indirect
|
||||
github.com/multiformats/go-multiaddr v0.5.0 // indirect
|
||||
@ -54,7 +56,6 @@ require (
|
||||
github.com/multiformats/go-varint v0.0.6 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_golang v1.13.0 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.37.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
@ -72,7 +73,5 @@ require (
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
lukechampine.com/blake3 v1.1.6 // indirect
|
||||
)
|
||||
|
||||
11
go.sum
11
go.sum
@ -63,8 +63,6 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cheggaaa/mb v1.0.3 h1:03ksWum+6kHclB+kjwKMaBtgl5gtNYUwNpxsHQciKe8=
|
||||
github.com/cheggaaa/mb v1.0.3/go.mod h1:NUl0GBtFLlfg2o6iZwxzcG7Lslc2wV/ADTFbLXtVPE4=
|
||||
github.com/cheggaaa/mb/v2 v2.0.1 h1:gn0khbEbKlw3i5VOYi0VnHEHayjZKfUDOyGSpHAybBs=
|
||||
github.com/cheggaaa/mb/v2 v2.0.1/go.mod h1:XGeZw20Iqgjky26KL0mvCwk3+4NyZCUbshSo6ALne+c=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
@ -117,6 +115,8 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
@ -145,10 +145,10 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
@ -435,7 +435,6 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@ -483,8 +482,6 @@ golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16CMAGuqwO2lX1mTyyRRc=
|
||||
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
@ -543,11 +540,11 @@ golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
//go:generate mockgen -destination mock_list/mock_list.go github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list ACLList
|
||||
package list
|
||||
|
||||
import (
|
||||
|
||||
222
pkg/acl/list/mock_list/mock_list.go
Normal file
222
pkg/acl/list/mock_list/mock_list.go
Normal file
@ -0,0 +1,222 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list (interfaces: ACLList)
|
||||
|
||||
// Package mock_list is a generated GoMock package.
|
||||
package mock_list
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
aclrecordproto "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclrecordproto"
|
||||
list "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/list"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockACLList is a mock of ACLList interface.
|
||||
type MockACLList struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockACLListMockRecorder
|
||||
}
|
||||
|
||||
// MockACLListMockRecorder is the mock recorder for MockACLList.
|
||||
type MockACLListMockRecorder struct {
|
||||
mock *MockACLList
|
||||
}
|
||||
|
||||
// NewMockACLList creates a new mock instance.
|
||||
func NewMockACLList(ctrl *gomock.Controller) *MockACLList {
|
||||
mock := &MockACLList{ctrl: ctrl}
|
||||
mock.recorder = &MockACLListMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockACLList) EXPECT() *MockACLListMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// ACLState mocks base method.
|
||||
func (m *MockACLList) ACLState() *list.ACLState {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ACLState")
|
||||
ret0, _ := ret[0].(*list.ACLState)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// ACLState indicates an expected call of ACLState.
|
||||
func (mr *MockACLListMockRecorder) ACLState() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ACLState", reflect.TypeOf((*MockACLList)(nil).ACLState))
|
||||
}
|
||||
|
||||
// Close mocks base method.
|
||||
func (m *MockACLList) Close() error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Close")
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Close indicates an expected call of Close.
|
||||
func (mr *MockACLListMockRecorder) Close() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockACLList)(nil).Close))
|
||||
}
|
||||
|
||||
// Get mocks base method.
|
||||
func (m *MockACLList) Get(arg0 string) (*list.ACLRecord, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Get", arg0)
|
||||
ret0, _ := ret[0].(*list.ACLRecord)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Get indicates an expected call of Get.
|
||||
func (mr *MockACLListMockRecorder) Get(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockACLList)(nil).Get), arg0)
|
||||
}
|
||||
|
||||
// Head mocks base method.
|
||||
func (m *MockACLList) Head() *list.ACLRecord {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Head")
|
||||
ret0, _ := ret[0].(*list.ACLRecord)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Head indicates an expected call of Head.
|
||||
func (mr *MockACLListMockRecorder) Head() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Head", reflect.TypeOf((*MockACLList)(nil).Head))
|
||||
}
|
||||
|
||||
// ID mocks base method.
|
||||
func (m *MockACLList) ID() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ID")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// ID indicates an expected call of ID.
|
||||
func (mr *MockACLListMockRecorder) ID() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockACLList)(nil).ID))
|
||||
}
|
||||
|
||||
// IsAfter mocks base method.
|
||||
func (m *MockACLList) IsAfter(arg0, arg1 string) (bool, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "IsAfter", arg0, arg1)
|
||||
ret0, _ := ret[0].(bool)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// IsAfter indicates an expected call of IsAfter.
|
||||
func (mr *MockACLListMockRecorder) IsAfter(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsAfter", reflect.TypeOf((*MockACLList)(nil).IsAfter), arg0, arg1)
|
||||
}
|
||||
|
||||
// Iterate mocks base method.
|
||||
func (m *MockACLList) Iterate(arg0 func(*list.ACLRecord) bool) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "Iterate", arg0)
|
||||
}
|
||||
|
||||
// Iterate indicates an expected call of Iterate.
|
||||
func (mr *MockACLListMockRecorder) Iterate(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Iterate", reflect.TypeOf((*MockACLList)(nil).Iterate), arg0)
|
||||
}
|
||||
|
||||
// IterateFrom mocks base method.
|
||||
func (m *MockACLList) IterateFrom(arg0 string, arg1 func(*list.ACLRecord) bool) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "IterateFrom", arg0, arg1)
|
||||
}
|
||||
|
||||
// IterateFrom indicates an expected call of IterateFrom.
|
||||
func (mr *MockACLListMockRecorder) IterateFrom(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateFrom", reflect.TypeOf((*MockACLList)(nil).IterateFrom), arg0, arg1)
|
||||
}
|
||||
|
||||
// Lock mocks base method.
|
||||
func (m *MockACLList) Lock() {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "Lock")
|
||||
}
|
||||
|
||||
// Lock indicates an expected call of Lock.
|
||||
func (mr *MockACLListMockRecorder) Lock() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Lock", reflect.TypeOf((*MockACLList)(nil).Lock))
|
||||
}
|
||||
|
||||
// RLock mocks base method.
|
||||
func (m *MockACLList) RLock() {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "RLock")
|
||||
}
|
||||
|
||||
// RLock indicates an expected call of RLock.
|
||||
func (mr *MockACLListMockRecorder) RLock() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RLock", reflect.TypeOf((*MockACLList)(nil).RLock))
|
||||
}
|
||||
|
||||
// RUnlock mocks base method.
|
||||
func (m *MockACLList) RUnlock() {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "RUnlock")
|
||||
}
|
||||
|
||||
// RUnlock indicates an expected call of RUnlock.
|
||||
func (mr *MockACLListMockRecorder) RUnlock() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RUnlock", reflect.TypeOf((*MockACLList)(nil).RUnlock))
|
||||
}
|
||||
|
||||
// Records mocks base method.
|
||||
func (m *MockACLList) Records() []*list.ACLRecord {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Records")
|
||||
ret0, _ := ret[0].([]*list.ACLRecord)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Records indicates an expected call of Records.
|
||||
func (mr *MockACLListMockRecorder) Records() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Records", reflect.TypeOf((*MockACLList)(nil).Records))
|
||||
}
|
||||
|
||||
// Root mocks base method.
|
||||
func (m *MockACLList) Root() *aclrecordproto.ACLRoot {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Root")
|
||||
ret0, _ := ret[0].(*aclrecordproto.ACLRoot)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Root indicates an expected call of Root.
|
||||
func (mr *MockACLListMockRecorder) Root() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Root", reflect.TypeOf((*MockACLList)(nil).Root))
|
||||
}
|
||||
|
||||
// Unlock mocks base method.
|
||||
func (m *MockACLList) Unlock() {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "Unlock")
|
||||
}
|
||||
|
||||
// Unlock indicates an expected call of Unlock.
|
||||
func (mr *MockACLListMockRecorder) Unlock() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Unlock", reflect.TypeOf((*MockACLList)(nil).Unlock))
|
||||
}
|
||||
@ -87,6 +87,11 @@ func NewInMemoryTreeStorage(
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t *inMemoryTreeStorage) HasChange(ctx context.Context, id string) (bool, error) {
|
||||
_, exists := t.changes[id]
|
||||
return exists, nil
|
||||
}
|
||||
|
||||
func (t *inMemoryTreeStorage) ID() (string, error) {
|
||||
t.RLock()
|
||||
defer t.RUnlock()
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
//go:generate mockgen -destination mock_storage/mock_storage.go github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage ListStorage,TreeStorage
|
||||
package storage
|
||||
|
||||
import (
|
||||
|
||||
237
pkg/acl/storage/mock_storage/mock_storage.go
Normal file
237
pkg/acl/storage/mock_storage/mock_storage.go
Normal file
@ -0,0 +1,237 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage (interfaces: ListStorage,TreeStorage)
|
||||
|
||||
// Package mock_storage is a generated GoMock package.
|
||||
package mock_storage
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
aclrecordproto "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclrecordproto"
|
||||
treechangeproto "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockListStorage is a mock of ListStorage interface.
|
||||
type MockListStorage struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockListStorageMockRecorder
|
||||
}
|
||||
|
||||
// MockListStorageMockRecorder is the mock recorder for MockListStorage.
|
||||
type MockListStorageMockRecorder struct {
|
||||
mock *MockListStorage
|
||||
}
|
||||
|
||||
// NewMockListStorage creates a new mock instance.
|
||||
func NewMockListStorage(ctrl *gomock.Controller) *MockListStorage {
|
||||
mock := &MockListStorage{ctrl: ctrl}
|
||||
mock.recorder = &MockListStorageMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockListStorage) EXPECT() *MockListStorageMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// AddRawRecord mocks base method.
|
||||
func (m *MockListStorage) AddRawRecord(arg0 context.Context, arg1 *aclrecordproto.RawACLRecordWithId) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AddRawRecord", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// AddRawRecord indicates an expected call of AddRawRecord.
|
||||
func (mr *MockListStorageMockRecorder) AddRawRecord(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRawRecord", reflect.TypeOf((*MockListStorage)(nil).AddRawRecord), arg0, arg1)
|
||||
}
|
||||
|
||||
// GetRawRecord mocks base method.
|
||||
func (m *MockListStorage) GetRawRecord(arg0 context.Context, arg1 string) (*aclrecordproto.RawACLRecordWithId, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetRawRecord", arg0, arg1)
|
||||
ret0, _ := ret[0].(*aclrecordproto.RawACLRecordWithId)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetRawRecord indicates an expected call of GetRawRecord.
|
||||
func (mr *MockListStorageMockRecorder) GetRawRecord(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRawRecord", reflect.TypeOf((*MockListStorage)(nil).GetRawRecord), arg0, arg1)
|
||||
}
|
||||
|
||||
// Head mocks base method.
|
||||
func (m *MockListStorage) Head() (*aclrecordproto.RawACLRecordWithId, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Head")
|
||||
ret0, _ := ret[0].(*aclrecordproto.RawACLRecordWithId)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Head indicates an expected call of Head.
|
||||
func (mr *MockListStorageMockRecorder) Head() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Head", reflect.TypeOf((*MockListStorage)(nil).Head))
|
||||
}
|
||||
|
||||
// ID mocks base method.
|
||||
func (m *MockListStorage) ID() (string, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ID")
|
||||
ret0, _ := ret[0].(string)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ID indicates an expected call of ID.
|
||||
func (mr *MockListStorageMockRecorder) ID() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockListStorage)(nil).ID))
|
||||
}
|
||||
|
||||
// Root mocks base method.
|
||||
func (m *MockListStorage) Root() (*aclrecordproto.RawACLRecordWithId, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Root")
|
||||
ret0, _ := ret[0].(*aclrecordproto.RawACLRecordWithId)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Root indicates an expected call of Root.
|
||||
func (mr *MockListStorageMockRecorder) Root() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Root", reflect.TypeOf((*MockListStorage)(nil).Root))
|
||||
}
|
||||
|
||||
// MockTreeStorage is a mock of TreeStorage interface.
|
||||
type MockTreeStorage struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockTreeStorageMockRecorder
|
||||
}
|
||||
|
||||
// MockTreeStorageMockRecorder is the mock recorder for MockTreeStorage.
|
||||
type MockTreeStorageMockRecorder struct {
|
||||
mock *MockTreeStorage
|
||||
}
|
||||
|
||||
// NewMockTreeStorage creates a new mock instance.
|
||||
func NewMockTreeStorage(ctrl *gomock.Controller) *MockTreeStorage {
|
||||
mock := &MockTreeStorage{ctrl: ctrl}
|
||||
mock.recorder = &MockTreeStorageMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockTreeStorage) EXPECT() *MockTreeStorageMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// AddRawChange mocks base method.
|
||||
func (m *MockTreeStorage) AddRawChange(arg0 *treechangeproto.RawTreeChangeWithId) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AddRawChange", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// AddRawChange indicates an expected call of AddRawChange.
|
||||
func (mr *MockTreeStorageMockRecorder) AddRawChange(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRawChange", reflect.TypeOf((*MockTreeStorage)(nil).AddRawChange), arg0)
|
||||
}
|
||||
|
||||
// GetRawChange mocks base method.
|
||||
func (m *MockTreeStorage) GetRawChange(arg0 context.Context, arg1 string) (*treechangeproto.RawTreeChangeWithId, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetRawChange", arg0, arg1)
|
||||
ret0, _ := ret[0].(*treechangeproto.RawTreeChangeWithId)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetRawChange indicates an expected call of GetRawChange.
|
||||
func (mr *MockTreeStorageMockRecorder) GetRawChange(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRawChange", reflect.TypeOf((*MockTreeStorage)(nil).GetRawChange), arg0, arg1)
|
||||
}
|
||||
|
||||
// HasChange mocks base method.
|
||||
func (m *MockTreeStorage) HasChange(arg0 context.Context, arg1 string) (bool, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "HasChange", arg0, arg1)
|
||||
ret0, _ := ret[0].(bool)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// HasChange indicates an expected call of HasChange.
|
||||
func (mr *MockTreeStorageMockRecorder) HasChange(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasChange", reflect.TypeOf((*MockTreeStorage)(nil).HasChange), arg0, arg1)
|
||||
}
|
||||
|
||||
// Heads mocks base method.
|
||||
func (m *MockTreeStorage) Heads() ([]string, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Heads")
|
||||
ret0, _ := ret[0].([]string)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Heads indicates an expected call of Heads.
|
||||
func (mr *MockTreeStorageMockRecorder) Heads() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Heads", reflect.TypeOf((*MockTreeStorage)(nil).Heads))
|
||||
}
|
||||
|
||||
// ID mocks base method.
|
||||
func (m *MockTreeStorage) ID() (string, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ID")
|
||||
ret0, _ := ret[0].(string)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ID indicates an expected call of ID.
|
||||
func (mr *MockTreeStorageMockRecorder) ID() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockTreeStorage)(nil).ID))
|
||||
}
|
||||
|
||||
// Root mocks base method.
|
||||
func (m *MockTreeStorage) Root() (*treechangeproto.RawTreeChangeWithId, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Root")
|
||||
ret0, _ := ret[0].(*treechangeproto.RawTreeChangeWithId)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Root indicates an expected call of Root.
|
||||
func (mr *MockTreeStorageMockRecorder) Root() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Root", reflect.TypeOf((*MockTreeStorage)(nil).Root))
|
||||
}
|
||||
|
||||
// SetHeads mocks base method.
|
||||
func (m *MockTreeStorage) SetHeads(arg0 []string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SetHeads", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SetHeads indicates an expected call of SetHeads.
|
||||
func (mr *MockTreeStorageMockRecorder) SetHeads(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetHeads", reflect.TypeOf((*MockTreeStorage)(nil).SetHeads), arg0)
|
||||
}
|
||||
@ -13,6 +13,7 @@ type TreeStorage interface {
|
||||
|
||||
AddRawChange(change *treechangeproto.RawTreeChangeWithId) error
|
||||
GetRawChange(ctx context.Context, id string) (*treechangeproto.RawTreeChangeWithId, error)
|
||||
HasChange(ctx context.Context, id string) (bool, error)
|
||||
}
|
||||
|
||||
type TreeStorageCreatorFunc = func(payload TreeStorageCreatePayload) (TreeStorage, error)
|
||||
|
||||
295
pkg/acl/tree/mock_objecttree/mock_objecttree.go
Normal file
295
pkg/acl/tree/mock_objecttree/mock_objecttree.go
Normal file
@ -0,0 +1,295 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree (interfaces: ObjectTree)
|
||||
|
||||
// Package mock_tree is a generated GoMock package.
|
||||
package mock_tree
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
storage "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage"
|
||||
tree "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree"
|
||||
treechangeproto "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockObjectTree is a mock of ObjectTree interface.
|
||||
type MockObjectTree struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockObjectTreeMockRecorder
|
||||
}
|
||||
|
||||
// MockObjectTreeMockRecorder is the mock recorder for MockObjectTree.
|
||||
type MockObjectTreeMockRecorder struct {
|
||||
mock *MockObjectTree
|
||||
}
|
||||
|
||||
// NewMockObjectTree creates a new mock instance.
|
||||
func NewMockObjectTree(ctrl *gomock.Controller) *MockObjectTree {
|
||||
mock := &MockObjectTree{ctrl: ctrl}
|
||||
mock.recorder = &MockObjectTreeMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockObjectTree) EXPECT() *MockObjectTreeMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// AddContent mocks base method.
|
||||
func (m *MockObjectTree) AddContent(arg0 context.Context, arg1 tree.SignableChangeContent) (tree.AddResult, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AddContent", arg0, arg1)
|
||||
ret0, _ := ret[0].(tree.AddResult)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// AddContent indicates an expected call of AddContent.
|
||||
func (mr *MockObjectTreeMockRecorder) AddContent(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddContent", reflect.TypeOf((*MockObjectTree)(nil).AddContent), arg0, arg1)
|
||||
}
|
||||
|
||||
// AddRawChanges mocks base method.
|
||||
func (m *MockObjectTree) AddRawChanges(arg0 context.Context, arg1 ...*treechangeproto.RawTreeChangeWithId) (tree.AddResult, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{arg0}
|
||||
for _, a := range arg1 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "AddRawChanges", varargs...)
|
||||
ret0, _ := ret[0].(tree.AddResult)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// AddRawChanges indicates an expected call of AddRawChanges.
|
||||
func (mr *MockObjectTreeMockRecorder) AddRawChanges(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]interface{}{arg0}, arg1...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRawChanges", reflect.TypeOf((*MockObjectTree)(nil).AddRawChanges), varargs...)
|
||||
}
|
||||
|
||||
// ChangesAfterCommonSnapshot mocks base method.
|
||||
func (m *MockObjectTree) ChangesAfterCommonSnapshot(arg0, arg1 []string) ([]*treechangeproto.RawTreeChangeWithId, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ChangesAfterCommonSnapshot", arg0, arg1)
|
||||
ret0, _ := ret[0].([]*treechangeproto.RawTreeChangeWithId)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ChangesAfterCommonSnapshot indicates an expected call of ChangesAfterCommonSnapshot.
|
||||
func (mr *MockObjectTreeMockRecorder) ChangesAfterCommonSnapshot(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChangesAfterCommonSnapshot", reflect.TypeOf((*MockObjectTree)(nil).ChangesAfterCommonSnapshot), arg0, arg1)
|
||||
}
|
||||
|
||||
// Close mocks base method.
|
||||
func (m *MockObjectTree) Close() error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Close")
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Close indicates an expected call of Close.
|
||||
func (mr *MockObjectTreeMockRecorder) Close() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockObjectTree)(nil).Close))
|
||||
}
|
||||
|
||||
// DebugDump mocks base method.
|
||||
func (m *MockObjectTree) DebugDump() (string, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DebugDump")
|
||||
ret0, _ := ret[0].(string)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// DebugDump indicates an expected call of DebugDump.
|
||||
func (mr *MockObjectTreeMockRecorder) DebugDump() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DebugDump", reflect.TypeOf((*MockObjectTree)(nil).DebugDump))
|
||||
}
|
||||
|
||||
// HasChanges mocks base method.
|
||||
func (m *MockObjectTree) HasChanges(arg0 ...string) bool {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{}
|
||||
for _, a := range arg0 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "HasChanges", varargs...)
|
||||
ret0, _ := ret[0].(bool)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HasChanges indicates an expected call of HasChanges.
|
||||
func (mr *MockObjectTreeMockRecorder) HasChanges(arg0 ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasChanges", reflect.TypeOf((*MockObjectTree)(nil).HasChanges), arg0...)
|
||||
}
|
||||
|
||||
// Header mocks base method.
|
||||
func (m *MockObjectTree) Header() *treechangeproto.RawTreeChangeWithId {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Header")
|
||||
ret0, _ := ret[0].(*treechangeproto.RawTreeChangeWithId)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Header indicates an expected call of Header.
|
||||
func (mr *MockObjectTreeMockRecorder) Header() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Header", reflect.TypeOf((*MockObjectTree)(nil).Header))
|
||||
}
|
||||
|
||||
// Heads mocks base method.
|
||||
func (m *MockObjectTree) Heads() []string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Heads")
|
||||
ret0, _ := ret[0].([]string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Heads indicates an expected call of Heads.
|
||||
func (mr *MockObjectTreeMockRecorder) Heads() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Heads", reflect.TypeOf((*MockObjectTree)(nil).Heads))
|
||||
}
|
||||
|
||||
// ID mocks base method.
|
||||
func (m *MockObjectTree) ID() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ID")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// ID indicates an expected call of ID.
|
||||
func (mr *MockObjectTreeMockRecorder) ID() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockObjectTree)(nil).ID))
|
||||
}
|
||||
|
||||
// Iterate mocks base method.
|
||||
func (m *MockObjectTree) Iterate(arg0 func([]byte) (interface{}, error), arg1 func(*tree.Change) bool) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Iterate", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Iterate indicates an expected call of Iterate.
|
||||
func (mr *MockObjectTreeMockRecorder) Iterate(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Iterate", reflect.TypeOf((*MockObjectTree)(nil).Iterate), arg0, arg1)
|
||||
}
|
||||
|
||||
// IterateFrom mocks base method.
|
||||
func (m *MockObjectTree) IterateFrom(arg0 string, arg1 func([]byte) (interface{}, error), arg2 func(*tree.Change) bool) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "IterateFrom", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// IterateFrom indicates an expected call of IterateFrom.
|
||||
func (mr *MockObjectTreeMockRecorder) IterateFrom(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateFrom", reflect.TypeOf((*MockObjectTree)(nil).IterateFrom), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// Lock mocks base method.
|
||||
func (m *MockObjectTree) Lock() {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "Lock")
|
||||
}
|
||||
|
||||
// Lock indicates an expected call of Lock.
|
||||
func (mr *MockObjectTreeMockRecorder) Lock() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Lock", reflect.TypeOf((*MockObjectTree)(nil).Lock))
|
||||
}
|
||||
|
||||
// RLock mocks base method.
|
||||
func (m *MockObjectTree) RLock() {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "RLock")
|
||||
}
|
||||
|
||||
// RLock indicates an expected call of RLock.
|
||||
func (mr *MockObjectTreeMockRecorder) RLock() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RLock", reflect.TypeOf((*MockObjectTree)(nil).RLock))
|
||||
}
|
||||
|
||||
// RUnlock mocks base method.
|
||||
func (m *MockObjectTree) RUnlock() {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "RUnlock")
|
||||
}
|
||||
|
||||
// RUnlock indicates an expected call of RUnlock.
|
||||
func (mr *MockObjectTreeMockRecorder) RUnlock() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RUnlock", reflect.TypeOf((*MockObjectTree)(nil).RUnlock))
|
||||
}
|
||||
|
||||
// Root mocks base method.
|
||||
func (m *MockObjectTree) Root() *tree.Change {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Root")
|
||||
ret0, _ := ret[0].(*tree.Change)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Root indicates an expected call of Root.
|
||||
func (mr *MockObjectTreeMockRecorder) Root() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Root", reflect.TypeOf((*MockObjectTree)(nil).Root))
|
||||
}
|
||||
|
||||
// SnapshotPath mocks base method.
|
||||
func (m *MockObjectTree) SnapshotPath() []string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SnapshotPath")
|
||||
ret0, _ := ret[0].([]string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SnapshotPath indicates an expected call of SnapshotPath.
|
||||
func (mr *MockObjectTreeMockRecorder) SnapshotPath() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SnapshotPath", reflect.TypeOf((*MockObjectTree)(nil).SnapshotPath))
|
||||
}
|
||||
|
||||
// Storage mocks base method.
|
||||
func (m *MockObjectTree) Storage() storage.TreeStorage {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Storage")
|
||||
ret0, _ := ret[0].(storage.TreeStorage)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Storage indicates an expected call of Storage.
|
||||
func (mr *MockObjectTreeMockRecorder) Storage() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Storage", reflect.TypeOf((*MockObjectTree)(nil).Storage))
|
||||
}
|
||||
|
||||
// Unlock mocks base method.
|
||||
func (m *MockObjectTree) Unlock() {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "Unlock")
|
||||
}
|
||||
|
||||
// Unlock indicates an expected call of Unlock.
|
||||
func (mr *MockObjectTreeMockRecorder) Unlock() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Unlock", reflect.TypeOf((*MockObjectTree)(nil).Unlock))
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
//go:generate mockgen -destination mock_objecttree/mock_objecttree.go github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree ObjectTree
|
||||
package tree
|
||||
|
||||
import (
|
||||
@ -42,7 +43,7 @@ type ObjectTree interface {
|
||||
Header() *treechangeproto.RawTreeChangeWithId
|
||||
Heads() []string
|
||||
Root() *Change
|
||||
HasChange(string) bool
|
||||
HasChanges(...string) bool
|
||||
DebugDump() (string, error)
|
||||
|
||||
Iterate(convert ChangeConvertFunc, iterate ChangeIterateFunc) error
|
||||
@ -75,7 +76,7 @@ type objectTree struct {
|
||||
|
||||
// buffers
|
||||
difSnapshotBuf []*treechangeproto.RawTreeChangeWithId
|
||||
tmpChangesBuf []*Change
|
||||
newChangesBuf []*Change
|
||||
newSnapshotsBuf []*Change
|
||||
notSeenIdxBuf []int
|
||||
|
||||
@ -226,7 +227,7 @@ func (ot *objectTree) AddRawChanges(ctx context.Context, rawChanges ...*treechan
|
||||
|
||||
func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*treechangeproto.RawTreeChangeWithId) (addResult AddResult, err error) {
|
||||
// resetting buffers
|
||||
ot.tmpChangesBuf = ot.tmpChangesBuf[:0]
|
||||
ot.newChangesBuf = ot.newChangesBuf[:0]
|
||||
ot.notSeenIdxBuf = ot.notSeenIdxBuf[:0]
|
||||
ot.difSnapshotBuf = ot.difSnapshotBuf[:0]
|
||||
ot.newSnapshotsBuf = ot.newSnapshotsBuf[:0]
|
||||
@ -246,20 +247,21 @@ func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*treechan
|
||||
if _, exists := ot.tree.attached[ch.Id]; exists {
|
||||
continue
|
||||
}
|
||||
if _, exists := ot.tree.unAttached[ch.Id]; exists {
|
||||
continue
|
||||
}
|
||||
|
||||
var change *Change
|
||||
change, err = ot.changeBuilder.ConvertFromRaw(ch, true)
|
||||
if err != nil {
|
||||
return
|
||||
if unAttached, exists := ot.tree.unAttached[ch.Id]; exists {
|
||||
change = unAttached
|
||||
} else {
|
||||
change, err = ot.changeBuilder.ConvertFromRaw(ch, true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if change.IsSnapshot {
|
||||
ot.newSnapshotsBuf = append(ot.newSnapshotsBuf, change)
|
||||
}
|
||||
ot.tmpChangesBuf = append(ot.tmpChangesBuf, change)
|
||||
ot.newChangesBuf = append(ot.newChangesBuf, change)
|
||||
ot.notSeenIdxBuf = append(ot.notSeenIdxBuf, idx)
|
||||
}
|
||||
|
||||
@ -273,6 +275,106 @@ func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*treechan
|
||||
return
|
||||
}
|
||||
|
||||
rollback := func(changes []*Change) {
|
||||
for _, ch := range changes {
|
||||
if _, exists := ot.tree.attached[ch.Id]; exists {
|
||||
delete(ot.tree.attached, ch.Id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// checks if we need to go to database
|
||||
isOldSnapshot := func(ch *Change) bool {
|
||||
if ch.SnapshotId == ot.tree.RootId() {
|
||||
return false
|
||||
}
|
||||
for _, sn := range ot.newSnapshotsBuf {
|
||||
// if change refers to newly received snapshot
|
||||
if ch.SnapshotId == sn.Id {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
shouldRebuildFromStorage := false
|
||||
// checking if we have some changes with different snapshot and then rebuilding
|
||||
for idx, ch := range ot.newChangesBuf {
|
||||
if isOldSnapshot(ch) {
|
||||
var exists bool
|
||||
// checking if it exists in the storage, if yes, then at some point it was added to the tree
|
||||
// thus we don't need to look at this change
|
||||
exists, err = ot.treeStorage.HasChange(ctx, ch.Id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if exists {
|
||||
// marking as nil to delete after
|
||||
ot.newChangesBuf[idx] = nil
|
||||
continue
|
||||
}
|
||||
// we haven't seen the change, and it refers to old snapshot, so we should rebuild
|
||||
shouldRebuildFromStorage = true
|
||||
}
|
||||
}
|
||||
// discarding all previously seen changes
|
||||
ot.newChangesBuf = discardFromSlice(ot.newChangesBuf, func(ch *Change) bool { return ch == nil })
|
||||
|
||||
if shouldRebuildFromStorage {
|
||||
err = ot.rebuildFromStorage(ot.newChangesBuf)
|
||||
if err != nil {
|
||||
// rebuilding without new changes
|
||||
ot.rebuildFromStorage(nil)
|
||||
return
|
||||
}
|
||||
addResult, err = ot.createAddResult(prevHeadsCopy, Rebuild, nil, rawChanges)
|
||||
if err != nil {
|
||||
// that means that some unattached changes were somehow corrupted in memory
|
||||
// this shouldn't happen but if that happens, then rebuilding from storage
|
||||
ot.rebuildFromStorage(nil)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// normal mode of operation, where we don't need to rebuild from database
|
||||
mode, treeChangesAdded := ot.tree.Add(ot.newChangesBuf...)
|
||||
switch mode {
|
||||
case Nothing:
|
||||
addResult = AddResult{
|
||||
OldHeads: prevHeadsCopy,
|
||||
Heads: prevHeadsCopy,
|
||||
Mode: mode,
|
||||
}
|
||||
return
|
||||
|
||||
default:
|
||||
// we need to validate only newly added changes
|
||||
err = ot.validateTree(treeChangesAdded)
|
||||
if err != nil {
|
||||
rollback(treeChangesAdded)
|
||||
err = ErrHasInvalidChanges
|
||||
return
|
||||
}
|
||||
addResult, err = ot.createAddResult(prevHeadsCopy, mode, treeChangesAdded, rawChanges)
|
||||
if err != nil {
|
||||
// that means that some unattached changes were somehow corrupted in memory
|
||||
// this shouldn't happen but if that happens, then rebuilding from storage
|
||||
ot.rebuildFromStorage(nil)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ot *objectTree) createAddResult(oldHeads []string, mode Mode, treeChangesAdded []*Change, rawChanges []*treechangeproto.RawTreeChangeWithId) (addResult AddResult, err error) {
|
||||
headsCopy := func() []string {
|
||||
newHeads := make([]string, 0, len(ot.tree.Heads()))
|
||||
newHeads = append(newHeads, ot.tree.Heads()...)
|
||||
return newHeads
|
||||
}
|
||||
|
||||
// returns changes that we added to the tree as attached this round
|
||||
// they can include not only the changes that were added now,
|
||||
// but also the changes that were previously in the tree
|
||||
@ -312,88 +414,16 @@ func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*treechan
|
||||
return
|
||||
}
|
||||
|
||||
rollback := func(changes []*Change) {
|
||||
for _, ch := range changes {
|
||||
if _, exists := ot.tree.attached[ch.Id]; exists {
|
||||
delete(ot.tree.attached, ch.Id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// checks if we need to go to database
|
||||
isOldSnapshot := func(ch *Change) bool {
|
||||
if ch.SnapshotId == ot.tree.RootId() {
|
||||
return false
|
||||
}
|
||||
for _, sn := range ot.newSnapshotsBuf {
|
||||
// if change refers to newly received snapshot
|
||||
if ch.SnapshotId == sn.Id {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// checking if we have some changes with different snapshot and then rebuilding
|
||||
for _, ch := range ot.tmpChangesBuf {
|
||||
if isOldSnapshot(ch) {
|
||||
err = ot.rebuildFromStorage(ot.tmpChangesBuf)
|
||||
if err != nil {
|
||||
// rebuilding without new changes
|
||||
ot.rebuildFromStorage(nil)
|
||||
return
|
||||
}
|
||||
var added []*treechangeproto.RawTreeChangeWithId
|
||||
added, err = getAddedChanges(nil)
|
||||
// we shouldn't get any error in this case
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
addResult = AddResult{
|
||||
OldHeads: prevHeadsCopy,
|
||||
Heads: headsCopy(),
|
||||
Added: added,
|
||||
Mode: Rebuild,
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// normal mode of operation, where we don't need to rebuild from database
|
||||
mode, treeChangesAdded := ot.tree.Add(ot.tmpChangesBuf...)
|
||||
switch mode {
|
||||
case Nothing:
|
||||
addResult = AddResult{
|
||||
OldHeads: prevHeadsCopy,
|
||||
Heads: prevHeadsCopy,
|
||||
Mode: mode,
|
||||
}
|
||||
var added []*treechangeproto.RawTreeChangeWithId
|
||||
added, err = getAddedChanges(treeChangesAdded)
|
||||
if err != nil {
|
||||
return
|
||||
|
||||
default:
|
||||
// we need to validate only newly added changes
|
||||
err = ot.validateTree(treeChangesAdded)
|
||||
if err != nil {
|
||||
rollback(treeChangesAdded)
|
||||
err = ErrHasInvalidChanges
|
||||
return
|
||||
}
|
||||
var added []*treechangeproto.RawTreeChangeWithId
|
||||
added, err = getAddedChanges(treeChangesAdded)
|
||||
if err != nil {
|
||||
// that means that some unattached changes were somehow corrupted in memory
|
||||
// this shouldn't happen but if that happens, then rebuilding from storage
|
||||
ot.rebuildFromStorage(nil)
|
||||
return
|
||||
}
|
||||
|
||||
addResult = AddResult{
|
||||
OldHeads: prevHeadsCopy,
|
||||
Heads: headsCopy(),
|
||||
Added: added,
|
||||
Mode: mode,
|
||||
}
|
||||
}
|
||||
addResult = AddResult{
|
||||
OldHeads: oldHeads,
|
||||
Heads: headsCopy(),
|
||||
Added: added,
|
||||
Mode: mode,
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -440,9 +470,28 @@ func (ot *objectTree) IterateFrom(id string, convert ChangeConvertFunc, iterate
|
||||
return
|
||||
}
|
||||
|
||||
func (ot *objectTree) HasChange(s string) bool {
|
||||
_, attachedExists := ot.tree.attached[s]
|
||||
return attachedExists
|
||||
func (ot *objectTree) HasChanges(chs ...string) bool {
|
||||
hasChange := func(s string) bool {
|
||||
_, attachedExists := ot.tree.attached[s]
|
||||
if attachedExists {
|
||||
return attachedExists
|
||||
}
|
||||
|
||||
has, err := ot.treeStorage.HasChange(context.Background(), s)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return has
|
||||
}
|
||||
|
||||
for _, ch := range chs {
|
||||
if !hasChange(ch) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (ot *objectTree) Heads() []string {
|
||||
|
||||
@ -104,7 +104,7 @@ func buildObjectTree(deps objectTreeDeps) (ObjectTree, error) {
|
||||
rawChangeLoader: deps.rawChangeLoader,
|
||||
tree: nil,
|
||||
keys: make(map[uint64]*symmetric.Key),
|
||||
tmpChangesBuf: make([]*Change, 0, 10),
|
||||
newChangesBuf: make([]*Change, 0, 10),
|
||||
difSnapshotBuf: make([]*treechangeproto.RawTreeChangeWithId, 0, 10),
|
||||
notSeenIdxBuf: make([]int, 0, 10),
|
||||
newSnapshotsBuf: make([]*Change, 0, 10),
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
//go:generate mockgen -destination mock_ldiff/mock_ldiff.go github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff Diff,Remote
|
||||
// Package ldiff provides a container of elements with fixed id and changeable content.
|
||||
// Diff can calculate the difference with another diff container (you can make it remote) with minimum hops and traffic.
|
||||
package ldiff
|
||||
|
||||
136
pkg/ldiff/mock_ldiff/mock_ldiff.go
Normal file
136
pkg/ldiff/mock_ldiff/mock_ldiff.go
Normal file
@ -0,0 +1,136 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff (interfaces: Diff,Remote)
|
||||
|
||||
// Package mock_ldiff is a generated GoMock package.
|
||||
package mock_ldiff
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
ldiff "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ldiff"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockDiff is a mock of Diff interface.
|
||||
type MockDiff struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockDiffMockRecorder
|
||||
}
|
||||
|
||||
// MockDiffMockRecorder is the mock recorder for MockDiff.
|
||||
type MockDiffMockRecorder struct {
|
||||
mock *MockDiff
|
||||
}
|
||||
|
||||
// NewMockDiff creates a new mock instance.
|
||||
func NewMockDiff(ctrl *gomock.Controller) *MockDiff {
|
||||
mock := &MockDiff{ctrl: ctrl}
|
||||
mock.recorder = &MockDiffMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockDiff) EXPECT() *MockDiffMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Diff mocks base method.
|
||||
func (m *MockDiff) Diff(arg0 context.Context, arg1 ldiff.Remote) ([]string, []string, []string, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Diff", arg0, arg1)
|
||||
ret0, _ := ret[0].([]string)
|
||||
ret1, _ := ret[1].([]string)
|
||||
ret2, _ := ret[2].([]string)
|
||||
ret3, _ := ret[3].(error)
|
||||
return ret0, ret1, ret2, ret3
|
||||
}
|
||||
|
||||
// Diff indicates an expected call of Diff.
|
||||
func (mr *MockDiffMockRecorder) Diff(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Diff", reflect.TypeOf((*MockDiff)(nil).Diff), arg0, arg1)
|
||||
}
|
||||
|
||||
// Ranges mocks base method.
|
||||
func (m *MockDiff) Ranges(arg0 context.Context, arg1 []ldiff.Range, arg2 []ldiff.RangeResult) ([]ldiff.RangeResult, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Ranges", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].([]ldiff.RangeResult)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Ranges indicates an expected call of Ranges.
|
||||
func (mr *MockDiffMockRecorder) Ranges(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ranges", reflect.TypeOf((*MockDiff)(nil).Ranges), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// RemoveId mocks base method.
|
||||
func (m *MockDiff) RemoveId(arg0 string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "RemoveId", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// RemoveId indicates an expected call of RemoveId.
|
||||
func (mr *MockDiffMockRecorder) RemoveId(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveId", reflect.TypeOf((*MockDiff)(nil).RemoveId), arg0)
|
||||
}
|
||||
|
||||
// Set mocks base method.
|
||||
func (m *MockDiff) Set(arg0 ...ldiff.Element) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{}
|
||||
for _, a := range arg0 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
m.ctrl.Call(m, "Set", varargs...)
|
||||
}
|
||||
|
||||
// Set indicates an expected call of Set.
|
||||
func (mr *MockDiffMockRecorder) Set(arg0 ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Set", reflect.TypeOf((*MockDiff)(nil).Set), arg0...)
|
||||
}
|
||||
|
||||
// MockRemote is a mock of Remote interface.
|
||||
type MockRemote struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockRemoteMockRecorder
|
||||
}
|
||||
|
||||
// MockRemoteMockRecorder is the mock recorder for MockRemote.
|
||||
type MockRemoteMockRecorder struct {
|
||||
mock *MockRemote
|
||||
}
|
||||
|
||||
// NewMockRemote creates a new mock instance.
|
||||
func NewMockRemote(ctrl *gomock.Controller) *MockRemote {
|
||||
mock := &MockRemote{ctrl: ctrl}
|
||||
mock.recorder = &MockRemoteMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockRemote) EXPECT() *MockRemoteMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Ranges mocks base method.
|
||||
func (m *MockRemote) Ranges(arg0 context.Context, arg1 []ldiff.Range, arg2 []ldiff.RangeResult) ([]ldiff.RangeResult, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Ranges", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].([]ldiff.RangeResult)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Ranges indicates an expected call of Ranges.
|
||||
func (mr *MockRemoteMockRecorder) Ranges(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ranges", reflect.TypeOf((*MockRemote)(nil).Ranges), arg0, arg1, arg2)
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user