mirror of
https://github.com/anyproto/any-sync.git
synced 2025-06-08 05:57:03 +09:00
Merge branch 'main' of github.com:anyproto/any-sync into add-content-with-validator
# Conflicts: # commonspace/object/tree/synctree/synctree_test.go
This commit is contained in:
commit
f56a3f1a08
53 changed files with 2026 additions and 464 deletions
|
@ -100,7 +100,7 @@ func (d *diffSyncer) Sync(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
d.log.DebugCtx(ctx, "start diffsync", zap.Strings("peerIds", peerIds))
|
d.log.DebugCtx(ctx, "start diffsync", zap.Strings("peerIds", peerIds))
|
||||||
for _, p := range peers {
|
for _, p := range peers {
|
||||||
if err = d.syncWithPeer(peer.CtxWithPeerId(ctx, p.Id()), p); err != nil {
|
if err = d.syncWithPeer(peer.CtxWithPeerAddr(ctx, p.Id()), p); err != nil {
|
||||||
d.log.ErrorCtx(ctx, "can't sync with peer", zap.String("peer", p.Id()), zap.Error(err))
|
d.log.ErrorCtx(ctx, "can't sync with peer", zap.String("peer", p.Id()), zap.Error(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,13 +152,13 @@ func (d *diffSyncer) syncWithPeer(ctx context.Context, p peer.Peer) (err error)
|
||||||
|
|
||||||
// if we removed acl head from the list
|
// if we removed acl head from the list
|
||||||
if len(existingIds) < prevExistingLen {
|
if len(existingIds) < prevExistingLen {
|
||||||
if syncErr := d.syncAcl.SyncWithPeer(ctx, p.Id()); syncErr != nil {
|
if syncErr := d.syncAcl.SyncWithPeer(ctx, p); syncErr != nil {
|
||||||
log.Warn("failed to send acl sync message to peer", zap.String("aclId", syncAclId))
|
log.Warn("failed to send acl sync message to peer", zap.String("aclId", syncAclId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// treeSyncer should not get acl id, that's why we filter existing ids before
|
// treeSyncer should not get acl id, that's why we filter existing ids before
|
||||||
err = d.treeSyncer.SyncAll(ctx, p.Id(), existingIds, missingIds)
|
err = d.treeSyncer.SyncAll(ctx, p, existingIds, missingIds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"go.uber.org/mock/gomock"
|
"go.uber.org/mock/gomock"
|
||||||
|
@ -18,6 +17,7 @@ import (
|
||||||
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
||||||
"github.com/anyproto/any-sync/consensus/consensusproto"
|
"github.com/anyproto/any-sync/consensus/consensusproto"
|
||||||
"github.com/anyproto/any-sync/net/peer"
|
"github.com/anyproto/any-sync/net/peer"
|
||||||
|
"github.com/anyproto/any-sync/net/rpc/rpctest"
|
||||||
)
|
)
|
||||||
|
|
||||||
type pushSpaceRequestMatcher struct {
|
type pushSpaceRequestMatcher struct {
|
||||||
|
@ -56,49 +56,6 @@ func (p pushSpaceRequestMatcher) String() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
type mockPeer struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m mockPeer) CloseChan() <-chan struct{} {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m mockPeer) SetTTL(ttl time.Duration) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m mockPeer) Id() string {
|
|
||||||
return "peerId"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m mockPeer) Context() context.Context {
|
|
||||||
return context.Background()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m mockPeer) AcquireDrpcConn(ctx context.Context) (drpc.Conn, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m mockPeer) ReleaseDrpcConn(conn drpc.Conn) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m mockPeer) DoDrpc(ctx context.Context, do func(conn drpc.Conn) error) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m mockPeer) IsClosed() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m mockPeer) TryClose(objectTTL time.Duration) (res bool, err error) {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m mockPeer) Close() (err error) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fx *headSyncFixture) initDiffSyncer(t *testing.T) {
|
func (fx *headSyncFixture) initDiffSyncer(t *testing.T) {
|
||||||
fx.init(t)
|
fx.init(t)
|
||||||
fx.diffSyncer = newDiffSyncer(fx.headSync).(*diffSyncer)
|
fx.diffSyncer = newDiffSyncer(fx.headSync).(*diffSyncer)
|
||||||
|
@ -116,7 +73,7 @@ func TestDiffSyncer(t *testing.T) {
|
||||||
fx := newHeadSyncFixture(t)
|
fx := newHeadSyncFixture(t)
|
||||||
fx.initDiffSyncer(t)
|
fx.initDiffSyncer(t)
|
||||||
defer fx.stop()
|
defer fx.stop()
|
||||||
mPeer := mockPeer{}
|
mPeer := rpctest.MockPeer{}
|
||||||
remDiff := NewRemoteDiff(fx.spaceState.SpaceId, fx.clientMock)
|
remDiff := NewRemoteDiff(fx.spaceState.SpaceId, fx.clientMock)
|
||||||
fx.aclMock.EXPECT().Id().AnyTimes().Return("aclId")
|
fx.aclMock.EXPECT().Id().AnyTimes().Return("aclId")
|
||||||
fx.treeSyncerMock.EXPECT().ShouldSync(gomock.Any()).Return(true)
|
fx.treeSyncerMock.EXPECT().ShouldSync(gomock.Any()).Return(true)
|
||||||
|
@ -131,7 +88,7 @@ func TestDiffSyncer(t *testing.T) {
|
||||||
fx.deletionStateMock.EXPECT().Filter([]string{"new"}).Return([]string{"new"}).Times(1)
|
fx.deletionStateMock.EXPECT().Filter([]string{"new"}).Return([]string{"new"}).Times(1)
|
||||||
fx.deletionStateMock.EXPECT().Filter([]string{"changed"}).Return([]string{"changed"}).Times(1)
|
fx.deletionStateMock.EXPECT().Filter([]string{"changed"}).Return([]string{"changed"}).Times(1)
|
||||||
fx.deletionStateMock.EXPECT().Filter(nil).Return(nil).Times(1)
|
fx.deletionStateMock.EXPECT().Filter(nil).Return(nil).Times(1)
|
||||||
fx.treeSyncerMock.EXPECT().SyncAll(gomock.Any(), mPeer.Id(), []string{"changed"}, []string{"new"}).Return(nil)
|
fx.treeSyncerMock.EXPECT().SyncAll(gomock.Any(), mPeer, []string{"changed"}, []string{"new"}).Return(nil)
|
||||||
require.NoError(t, fx.diffSyncer.Sync(ctx))
|
require.NoError(t, fx.diffSyncer.Sync(ctx))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -139,7 +96,7 @@ func TestDiffSyncer(t *testing.T) {
|
||||||
fx := newHeadSyncFixture(t)
|
fx := newHeadSyncFixture(t)
|
||||||
fx.initDiffSyncer(t)
|
fx.initDiffSyncer(t)
|
||||||
defer fx.stop()
|
defer fx.stop()
|
||||||
mPeer := mockPeer{}
|
mPeer := rpctest.MockPeer{}
|
||||||
remDiff := NewRemoteDiff(fx.spaceState.SpaceId, fx.clientMock)
|
remDiff := NewRemoteDiff(fx.spaceState.SpaceId, fx.clientMock)
|
||||||
fx.treeSyncerMock.EXPECT().ShouldSync(gomock.Any()).Return(true)
|
fx.treeSyncerMock.EXPECT().ShouldSync(gomock.Any()).Return(true)
|
||||||
fx.aclMock.EXPECT().Id().AnyTimes().Return("aclId")
|
fx.aclMock.EXPECT().Id().AnyTimes().Return("aclId")
|
||||||
|
@ -154,8 +111,8 @@ func TestDiffSyncer(t *testing.T) {
|
||||||
fx.deletionStateMock.EXPECT().Filter([]string{"new"}).Return([]string{"new"}).Times(1)
|
fx.deletionStateMock.EXPECT().Filter([]string{"new"}).Return([]string{"new"}).Times(1)
|
||||||
fx.deletionStateMock.EXPECT().Filter([]string{"changed"}).Return([]string{"changed", "aclId"}).Times(1)
|
fx.deletionStateMock.EXPECT().Filter([]string{"changed"}).Return([]string{"changed", "aclId"}).Times(1)
|
||||||
fx.deletionStateMock.EXPECT().Filter(nil).Return(nil).Times(1)
|
fx.deletionStateMock.EXPECT().Filter(nil).Return(nil).Times(1)
|
||||||
fx.treeSyncerMock.EXPECT().SyncAll(gomock.Any(), mPeer.Id(), []string{"changed"}, []string{"new"}).Return(nil)
|
fx.treeSyncerMock.EXPECT().SyncAll(gomock.Any(), mPeer, []string{"changed"}, []string{"new"}).Return(nil)
|
||||||
fx.aclMock.EXPECT().SyncWithPeer(gomock.Any(), mPeer.Id()).Return(nil)
|
fx.aclMock.EXPECT().SyncWithPeer(gomock.Any(), mPeer).Return(nil)
|
||||||
require.NoError(t, fx.diffSyncer.Sync(ctx))
|
require.NoError(t, fx.diffSyncer.Sync(ctx))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -225,7 +182,7 @@ func TestDiffSyncer(t *testing.T) {
|
||||||
|
|
||||||
fx.peerManagerMock.EXPECT().
|
fx.peerManagerMock.EXPECT().
|
||||||
GetResponsiblePeers(gomock.Any()).
|
GetResponsiblePeers(gomock.Any()).
|
||||||
Return([]peer.Peer{mockPeer{}}, nil)
|
Return([]peer.Peer{rpctest.MockPeer{}}, nil)
|
||||||
fx.diffContainerMock.EXPECT().
|
fx.diffContainerMock.EXPECT().
|
||||||
DiffTypeCheck(gomock.Any(), gomock.Eq(remDiff)).Return(true, fx.diffMock, nil)
|
DiffTypeCheck(gomock.Any(), gomock.Eq(remDiff)).Return(true, fx.diffMock, nil)
|
||||||
fx.diffMock.EXPECT().
|
fx.diffMock.EXPECT().
|
||||||
|
@ -261,7 +218,7 @@ func TestDiffSyncer(t *testing.T) {
|
||||||
fx.treeSyncerMock.EXPECT().ShouldSync(gomock.Any()).Return(true)
|
fx.treeSyncerMock.EXPECT().ShouldSync(gomock.Any()).Return(true)
|
||||||
fx.peerManagerMock.EXPECT().
|
fx.peerManagerMock.EXPECT().
|
||||||
GetResponsiblePeers(gomock.Any()).
|
GetResponsiblePeers(gomock.Any()).
|
||||||
Return([]peer.Peer{mockPeer{}}, nil)
|
Return([]peer.Peer{rpctest.MockPeer{}}, nil)
|
||||||
fx.diffContainerMock.EXPECT().
|
fx.diffContainerMock.EXPECT().
|
||||||
DiffTypeCheck(gomock.Any(), gomock.Eq(remDiff)).Return(true, fx.diffMock, nil)
|
DiffTypeCheck(gomock.Any(), gomock.Eq(remDiff)).Return(true, fx.diffMock, nil)
|
||||||
fx.diffMock.EXPECT().
|
fx.diffMock.EXPECT().
|
||||||
|
@ -275,7 +232,7 @@ func TestDiffSyncer(t *testing.T) {
|
||||||
fx := newHeadSyncFixture(t)
|
fx := newHeadSyncFixture(t)
|
||||||
fx.initDiffSyncer(t)
|
fx.initDiffSyncer(t)
|
||||||
defer fx.stop()
|
defer fx.stop()
|
||||||
mPeer := mockPeer{}
|
mPeer := rpctest.MockPeer{}
|
||||||
remDiff := NewRemoteDiff(fx.spaceState.SpaceId, fx.clientMock)
|
remDiff := NewRemoteDiff(fx.spaceState.SpaceId, fx.clientMock)
|
||||||
fx.treeSyncerMock.EXPECT().ShouldSync(gomock.Any()).Return(true)
|
fx.treeSyncerMock.EXPECT().ShouldSync(gomock.Any()).Return(true)
|
||||||
fx.aclMock.EXPECT().Id().AnyTimes().Return("aclId")
|
fx.aclMock.EXPECT().Id().AnyTimes().Return("aclId")
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
headupdater "github.com/anyproto/any-sync/commonspace/object/acl/syncacl/headupdater"
|
headupdater "github.com/anyproto/any-sync/commonspace/object/acl/syncacl/headupdater"
|
||||||
spacesyncproto "github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
spacesyncproto "github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
||||||
consensusproto "github.com/anyproto/any-sync/consensus/consensusproto"
|
consensusproto "github.com/anyproto/any-sync/consensus/consensusproto"
|
||||||
|
peer "github.com/anyproto/any-sync/net/peer"
|
||||||
crypto "github.com/anyproto/any-sync/util/crypto"
|
crypto "github.com/anyproto/any-sync/util/crypto"
|
||||||
gomock "go.uber.org/mock/gomock"
|
gomock "go.uber.org/mock/gomock"
|
||||||
)
|
)
|
||||||
|
@ -132,17 +133,17 @@ func (mr *MockSyncAclMockRecorder) GetIndex(arg0 any) *gomock.Call {
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleMessage mocks base method.
|
// HandleMessage mocks base method.
|
||||||
func (m *MockSyncAcl) HandleMessage(arg0 context.Context, arg1 string, arg2 *spacesyncproto.ObjectSyncMessage) error {
|
func (m *MockSyncAcl) HandleMessage(arg0 context.Context, arg1 string, arg2 uint32, arg3 *spacesyncproto.ObjectSyncMessage) error {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "HandleMessage", arg0, arg1, arg2)
|
ret := m.ctrl.Call(m, "HandleMessage", arg0, arg1, arg2, arg3)
|
||||||
ret0, _ := ret[0].(error)
|
ret0, _ := ret[0].(error)
|
||||||
return ret0
|
return ret0
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleMessage indicates an expected call of HandleMessage.
|
// HandleMessage indicates an expected call of HandleMessage.
|
||||||
func (mr *MockSyncAclMockRecorder) HandleMessage(arg0, arg1, arg2 any) *gomock.Call {
|
func (mr *MockSyncAclMockRecorder) HandleMessage(arg0, arg1, arg2, arg3 any) *gomock.Call {
|
||||||
mr.mock.ctrl.T.Helper()
|
mr.mock.ctrl.T.Helper()
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleMessage", reflect.TypeOf((*MockSyncAcl)(nil).HandleMessage), arg0, arg1, arg2)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleMessage", reflect.TypeOf((*MockSyncAcl)(nil).HandleMessage), arg0, arg1, arg2, arg3)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleRequest mocks base method.
|
// HandleRequest mocks base method.
|
||||||
|
@ -430,7 +431,7 @@ func (mr *MockSyncAclMockRecorder) SetHeadUpdater(arg0 any) *gomock.Call {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SyncWithPeer mocks base method.
|
// SyncWithPeer mocks base method.
|
||||||
func (m *MockSyncAcl) SyncWithPeer(arg0 context.Context, arg1 string) error {
|
func (m *MockSyncAcl) SyncWithPeer(arg0 context.Context, arg1 peer.Peer) error {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "SyncWithPeer", arg0, arg1)
|
ret := m.ctrl.Call(m, "SyncWithPeer", arg0, arg1)
|
||||||
ret0, _ := ret[0].(error)
|
ret0, _ := ret[0].(error)
|
||||||
|
@ -504,6 +505,20 @@ func (mr *MockSyncClientMockRecorder) Broadcast(arg0 any) *gomock.Call {
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Broadcast", reflect.TypeOf((*MockSyncClient)(nil).Broadcast), arg0)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Broadcast", reflect.TypeOf((*MockSyncClient)(nil).Broadcast), arg0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateEmptyFullSyncRequest mocks base method.
|
||||||
|
func (m *MockSyncClient) CreateEmptyFullSyncRequest(arg0 list.AclList) *consensusproto.LogSyncMessage {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "CreateEmptyFullSyncRequest", arg0)
|
||||||
|
ret0, _ := ret[0].(*consensusproto.LogSyncMessage)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateEmptyFullSyncRequest indicates an expected call of CreateEmptyFullSyncRequest.
|
||||||
|
func (mr *MockSyncClientMockRecorder) CreateEmptyFullSyncRequest(arg0 any) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateEmptyFullSyncRequest", reflect.TypeOf((*MockSyncClient)(nil).CreateEmptyFullSyncRequest), arg0)
|
||||||
|
}
|
||||||
|
|
||||||
// CreateFullSyncRequest mocks base method.
|
// CreateFullSyncRequest mocks base method.
|
||||||
func (m *MockSyncClient) CreateFullSyncRequest(arg0 list.AclList, arg1 string) (*consensusproto.LogSyncMessage, error) {
|
func (m *MockSyncClient) CreateFullSyncRequest(arg0 list.AclList, arg1 string) (*consensusproto.LogSyncMessage, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
@ -614,6 +629,20 @@ func (m *MockRequestFactory) EXPECT() *MockRequestFactoryMockRecorder {
|
||||||
return m.recorder
|
return m.recorder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateEmptyFullSyncRequest mocks base method.
|
||||||
|
func (m *MockRequestFactory) CreateEmptyFullSyncRequest(arg0 list.AclList) *consensusproto.LogSyncMessage {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "CreateEmptyFullSyncRequest", arg0)
|
||||||
|
ret0, _ := ret[0].(*consensusproto.LogSyncMessage)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateEmptyFullSyncRequest indicates an expected call of CreateEmptyFullSyncRequest.
|
||||||
|
func (mr *MockRequestFactoryMockRecorder) CreateEmptyFullSyncRequest(arg0 any) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateEmptyFullSyncRequest", reflect.TypeOf((*MockRequestFactory)(nil).CreateEmptyFullSyncRequest), arg0)
|
||||||
|
}
|
||||||
|
|
||||||
// CreateFullSyncRequest mocks base method.
|
// CreateFullSyncRequest mocks base method.
|
||||||
func (m *MockRequestFactory) CreateFullSyncRequest(arg0 list.AclList, arg1 string) (*consensusproto.LogSyncMessage, error) {
|
func (m *MockRequestFactory) CreateFullSyncRequest(arg0 list.AclList, arg1 string) (*consensusproto.LogSyncMessage, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
|
|
||||||
type RequestFactory interface {
|
type RequestFactory interface {
|
||||||
CreateHeadUpdate(l list.AclList, added []*consensusproto.RawRecordWithId) (msg *consensusproto.LogSyncMessage)
|
CreateHeadUpdate(l list.AclList, added []*consensusproto.RawRecordWithId) (msg *consensusproto.LogSyncMessage)
|
||||||
|
CreateEmptyFullSyncRequest(l list.AclList) (req *consensusproto.LogSyncMessage)
|
||||||
CreateFullSyncRequest(l list.AclList, theirHead string) (req *consensusproto.LogSyncMessage, err error)
|
CreateFullSyncRequest(l list.AclList, theirHead string) (req *consensusproto.LogSyncMessage, err error)
|
||||||
CreateFullSyncResponse(l list.AclList, theirHead string) (*consensusproto.LogSyncMessage, error)
|
CreateFullSyncResponse(l list.AclList, theirHead string) (*consensusproto.LogSyncMessage, error)
|
||||||
}
|
}
|
||||||
|
@ -26,6 +27,13 @@ func (r *requestFactory) CreateHeadUpdate(l list.AclList, added []*consensusprot
|
||||||
}, l.Root())
|
}, l.Root())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *requestFactory) CreateEmptyFullSyncRequest(l list.AclList) (req *consensusproto.LogSyncMessage) {
|
||||||
|
// this is only sent to newer versions of the protocol
|
||||||
|
return consensusproto.WrapFullRequest(&consensusproto.LogFullSyncRequest{
|
||||||
|
Head: l.Head().Id,
|
||||||
|
}, l.Root())
|
||||||
|
}
|
||||||
|
|
||||||
func (r *requestFactory) CreateFullSyncRequest(l list.AclList, theirHead string) (req *consensusproto.LogSyncMessage, err error) {
|
func (r *requestFactory) CreateFullSyncRequest(l list.AclList, theirHead string) (req *consensusproto.LogSyncMessage, err error) {
|
||||||
if !l.HasHead(theirHead) {
|
if !l.HasHead(theirHead) {
|
||||||
return consensusproto.WrapFullRequest(&consensusproto.LogFullSyncRequest{
|
return consensusproto.WrapFullRequest(&consensusproto.LogFullSyncRequest{
|
||||||
|
|
|
@ -8,6 +8,8 @@ import (
|
||||||
|
|
||||||
"github.com/anyproto/any-sync/commonspace/object/acl/syncacl/headupdater"
|
"github.com/anyproto/any-sync/commonspace/object/acl/syncacl/headupdater"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/syncobjectgetter"
|
"github.com/anyproto/any-sync/commonspace/object/syncobjectgetter"
|
||||||
|
"github.com/anyproto/any-sync/net/peer"
|
||||||
|
"github.com/anyproto/any-sync/net/secureservice"
|
||||||
|
|
||||||
"github.com/anyproto/any-sync/accountservice"
|
"github.com/anyproto/any-sync/accountservice"
|
||||||
"github.com/anyproto/any-sync/app"
|
"github.com/anyproto/any-sync/app"
|
||||||
|
@ -35,7 +37,7 @@ type SyncAcl interface {
|
||||||
list.AclList
|
list.AclList
|
||||||
syncobjectgetter.SyncObject
|
syncobjectgetter.SyncObject
|
||||||
SetHeadUpdater(updater headupdater.HeadUpdater)
|
SetHeadUpdater(updater headupdater.HeadUpdater)
|
||||||
SyncWithPeer(ctx context.Context, peerId string) (err error)
|
SyncWithPeer(ctx context.Context, p peer.Peer) (err error)
|
||||||
SetAclUpdater(updater headupdater.AclUpdater)
|
SetAclUpdater(updater headupdater.AclUpdater)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,8 +75,8 @@ func (s *syncAcl) SetHeadUpdater(updater headupdater.HeadUpdater) {
|
||||||
s.headUpdater = updater
|
s.headUpdater = updater
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *syncAcl) HandleMessage(ctx context.Context, senderId string, request *spacesyncproto.ObjectSyncMessage) (err error) {
|
func (s *syncAcl) HandleMessage(ctx context.Context, senderId string, protoVersion uint32, request *spacesyncproto.ObjectSyncMessage) (err error) {
|
||||||
return s.syncHandler.HandleMessage(ctx, senderId, request)
|
return s.syncHandler.HandleMessage(ctx, senderId, protoVersion, request)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *syncAcl) Init(a *app.App) (err error) {
|
func (s *syncAcl) Init(a *app.App) (err error) {
|
||||||
|
@ -136,11 +138,18 @@ func (s *syncAcl) AddRawRecords(rawRecords []*consensusproto.RawRecordWithId) (e
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *syncAcl) SyncWithPeer(ctx context.Context, peerId string) (err error) {
|
func (s *syncAcl) SyncWithPeer(ctx context.Context, p peer.Peer) (err error) {
|
||||||
s.Lock()
|
s.Lock()
|
||||||
defer s.Unlock()
|
defer s.Unlock()
|
||||||
headUpdate := s.syncClient.CreateHeadUpdate(s, nil)
|
protoVersion, err := peer.CtxProtoVersion(p.Context())
|
||||||
return s.syncClient.SendUpdate(peerId, headUpdate)
|
// this works with old protocol
|
||||||
|
if err != nil || protoVersion <= secureservice.ProtoVersion {
|
||||||
|
headUpdate := s.syncClient.CreateHeadUpdate(s, nil)
|
||||||
|
return s.syncClient.SendUpdate(p.Id(), headUpdate)
|
||||||
|
}
|
||||||
|
// for new protocol sending empty request
|
||||||
|
request := s.syncClient.CreateEmptyFullSyncRequest(s)
|
||||||
|
return s.syncClient.QueueRequest(p.Id(), request)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *syncAcl) Close(ctx context.Context) (err error) {
|
func (s *syncAcl) Close(ctx context.Context) (err error) {
|
||||||
|
|
56
commonspace/object/acl/syncacl/syncacl_test.go
Normal file
56
commonspace/object/acl/syncacl/syncacl_test.go
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
package syncacl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"go.uber.org/mock/gomock"
|
||||||
|
|
||||||
|
"github.com/anyproto/any-sync/commonspace/object/acl/list/mock_list"
|
||||||
|
"github.com/anyproto/any-sync/commonspace/object/acl/syncacl/mock_syncacl"
|
||||||
|
"github.com/anyproto/any-sync/consensus/consensusproto"
|
||||||
|
"github.com/anyproto/any-sync/net/peer"
|
||||||
|
"github.com/anyproto/any-sync/net/rpc/rpctest"
|
||||||
|
"github.com/anyproto/any-sync/net/secureservice"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ctx = context.Background()
|
||||||
|
|
||||||
|
func TestSyncAcl_SyncWithPeer(t *testing.T) {
|
||||||
|
// this component will be rewritten, so no need for fixture now
|
||||||
|
t.Run("sync with old peer", func(t *testing.T) {
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
acl := mock_list.NewMockAclList(ctrl)
|
||||||
|
s := &syncAcl{AclList: acl}
|
||||||
|
defer ctrl.Finish()
|
||||||
|
mockClient := mock_syncacl.NewMockSyncClient(ctrl)
|
||||||
|
s.syncClient = mockClient
|
||||||
|
ctx := peer.CtxWithProtoVersion(ctx, secureservice.ProtoVersion)
|
||||||
|
pr := rpctest.MockPeer{Ctx: ctx}
|
||||||
|
retMsg := &consensusproto.LogSyncMessage{}
|
||||||
|
mockClient.EXPECT().CreateHeadUpdate(s, nil).Return(retMsg)
|
||||||
|
acl.EXPECT().Lock()
|
||||||
|
acl.EXPECT().Unlock()
|
||||||
|
mockClient.EXPECT().SendUpdate("peerId", retMsg).Return(nil)
|
||||||
|
err := s.SyncWithPeer(ctx, &pr)
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
t.Run("sync with new peer", func(t *testing.T) {
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
acl := mock_list.NewMockAclList(ctrl)
|
||||||
|
s := &syncAcl{AclList: acl}
|
||||||
|
defer ctrl.Finish()
|
||||||
|
mockClient := mock_syncacl.NewMockSyncClient(ctrl)
|
||||||
|
s.syncClient = mockClient
|
||||||
|
ctx := peer.CtxWithProtoVersion(ctx, secureservice.NewSyncProtoVersion)
|
||||||
|
pr := rpctest.MockPeer{Ctx: ctx}
|
||||||
|
req := &consensusproto.LogSyncMessage{}
|
||||||
|
mockClient.EXPECT().CreateEmptyFullSyncRequest(s).Return(req)
|
||||||
|
acl.EXPECT().Lock()
|
||||||
|
acl.EXPECT().Unlock()
|
||||||
|
mockClient.EXPECT().QueueRequest("peerId", req).Return(nil)
|
||||||
|
err := s.SyncWithPeer(ctx, &pr)
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
}
|
|
@ -4,12 +4,14 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
|
"github.com/gogo/protobuf/proto"
|
||||||
|
|
||||||
"github.com/anyproto/any-sync/commonspace/object/acl/list"
|
"github.com/anyproto/any-sync/commonspace/object/acl/list"
|
||||||
"github.com/anyproto/any-sync/commonspace/objectsync/synchandler"
|
"github.com/anyproto/any-sync/commonspace/objectsync/synchandler"
|
||||||
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
||||||
"github.com/anyproto/any-sync/commonspace/syncstatus"
|
"github.com/anyproto/any-sync/commonspace/syncstatus"
|
||||||
"github.com/anyproto/any-sync/consensus/consensusproto"
|
"github.com/anyproto/any-sync/consensus/consensusproto"
|
||||||
"github.com/gogo/protobuf/proto"
|
"github.com/anyproto/any-sync/net/secureservice"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -35,7 +37,7 @@ func newSyncAclHandler(spaceId string, aclList list.AclList, syncClient SyncClie
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *syncAclHandler) HandleMessage(ctx context.Context, senderId string, message *spacesyncproto.ObjectSyncMessage) (err error) {
|
func (s *syncAclHandler) HandleMessage(ctx context.Context, senderId string, protoVersion uint32, message *spacesyncproto.ObjectSyncMessage) (err error) {
|
||||||
unmarshalled := &consensusproto.LogSyncMessage{}
|
unmarshalled := &consensusproto.LogSyncMessage{}
|
||||||
err = proto.Unmarshal(message.Payload, unmarshalled)
|
err = proto.Unmarshal(message.Payload, unmarshalled)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -57,7 +59,18 @@ func (s *syncAclHandler) HandleMessage(ctx context.Context, senderId string, mes
|
||||||
case content.GetFullSyncRequest() != nil:
|
case content.GetFullSyncRequest() != nil:
|
||||||
return ErrMessageIsRequest
|
return ErrMessageIsRequest
|
||||||
case content.GetFullSyncResponse() != nil:
|
case content.GetFullSyncResponse() != nil:
|
||||||
return s.syncProtocol.FullSyncResponse(ctx, senderId, content.GetFullSyncResponse())
|
err := s.syncProtocol.FullSyncResponse(ctx, senderId, content.GetFullSyncResponse())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if protoVersion <= secureservice.ProtoVersion || s.aclList.Head().Id == head {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
req, err := s.syncClient.CreateFullSyncRequest(s.aclList, head)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return s.syncClient.QueueRequest(senderId, req)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,16 +3,20 @@ package syncacl
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gogo/protobuf/proto"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"go.uber.org/mock/gomock"
|
||||||
|
|
||||||
|
"github.com/anyproto/any-sync/commonspace/object/acl/list"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/acl/list/mock_list"
|
"github.com/anyproto/any-sync/commonspace/object/acl/list/mock_list"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/acl/syncacl/mock_syncacl"
|
"github.com/anyproto/any-sync/commonspace/object/acl/syncacl/mock_syncacl"
|
||||||
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
||||||
"github.com/anyproto/any-sync/commonspace/syncstatus"
|
"github.com/anyproto/any-sync/commonspace/syncstatus"
|
||||||
"github.com/anyproto/any-sync/consensus/consensusproto"
|
"github.com/anyproto/any-sync/consensus/consensusproto"
|
||||||
"github.com/gogo/protobuf/proto"
|
"github.com/anyproto/any-sync/net/secureservice"
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"go.uber.org/mock/gomock"
|
|
||||||
"sync"
|
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type testAclMock struct {
|
type testAclMock struct {
|
||||||
|
@ -110,7 +114,7 @@ func TestSyncAclHandler_HandleMessage(t *testing.T) {
|
||||||
fx.syncProtocolMock.EXPECT().HeadUpdate(ctx, fx.senderId, gomock.Any()).Return(syncReq, nil)
|
fx.syncProtocolMock.EXPECT().HeadUpdate(ctx, fx.senderId, gomock.Any()).Return(syncReq, nil)
|
||||||
fx.syncClientMock.EXPECT().QueueRequest(fx.senderId, syncReq).Return(nil)
|
fx.syncClientMock.EXPECT().QueueRequest(fx.senderId, syncReq).Return(nil)
|
||||||
|
|
||||||
err := fx.syncHandler.HandleMessage(ctx, fx.senderId, objectMsg)
|
err := fx.syncHandler.HandleMessage(ctx, fx.senderId, 0, objectMsg)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
t.Run("handle head update, no request", func(t *testing.T) {
|
t.Run("handle head update, no request", func(t *testing.T) {
|
||||||
|
@ -127,7 +131,7 @@ func TestSyncAclHandler_HandleMessage(t *testing.T) {
|
||||||
fx.aclMock.EXPECT().Id().AnyTimes().Return(fx.aclId)
|
fx.aclMock.EXPECT().Id().AnyTimes().Return(fx.aclId)
|
||||||
fx.syncProtocolMock.EXPECT().HeadUpdate(ctx, fx.senderId, gomock.Any()).Return(nil, nil)
|
fx.syncProtocolMock.EXPECT().HeadUpdate(ctx, fx.senderId, gomock.Any()).Return(nil, nil)
|
||||||
|
|
||||||
err := fx.syncHandler.HandleMessage(ctx, fx.senderId, objectMsg)
|
err := fx.syncHandler.HandleMessage(ctx, fx.senderId, 0, objectMsg)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
t.Run("handle head update, returned error", func(t *testing.T) {
|
t.Run("handle head update, returned error", func(t *testing.T) {
|
||||||
|
@ -145,7 +149,7 @@ func TestSyncAclHandler_HandleMessage(t *testing.T) {
|
||||||
expectedErr := fmt.Errorf("some error")
|
expectedErr := fmt.Errorf("some error")
|
||||||
fx.syncProtocolMock.EXPECT().HeadUpdate(ctx, fx.senderId, gomock.Any()).Return(nil, expectedErr)
|
fx.syncProtocolMock.EXPECT().HeadUpdate(ctx, fx.senderId, gomock.Any()).Return(nil, expectedErr)
|
||||||
|
|
||||||
err := fx.syncHandler.HandleMessage(ctx, fx.senderId, objectMsg)
|
err := fx.syncHandler.HandleMessage(ctx, fx.senderId, 0, objectMsg)
|
||||||
require.Error(t, expectedErr, err)
|
require.Error(t, expectedErr, err)
|
||||||
})
|
})
|
||||||
t.Run("handle full sync request is forbidden", func(t *testing.T) {
|
t.Run("handle full sync request is forbidden", func(t *testing.T) {
|
||||||
|
@ -160,7 +164,7 @@ func TestSyncAclHandler_HandleMessage(t *testing.T) {
|
||||||
objectMsg, _ := spacesyncproto.MarshallSyncMessage(logMessage, fx.spaceId, fx.aclId)
|
objectMsg, _ := spacesyncproto.MarshallSyncMessage(logMessage, fx.spaceId, fx.aclId)
|
||||||
|
|
||||||
fx.aclMock.EXPECT().Id().AnyTimes().Return(fx.aclId)
|
fx.aclMock.EXPECT().Id().AnyTimes().Return(fx.aclId)
|
||||||
err := fx.syncHandler.HandleMessage(ctx, fx.senderId, objectMsg)
|
err := fx.syncHandler.HandleMessage(ctx, fx.senderId, 0, objectMsg)
|
||||||
require.Error(t, ErrMessageIsRequest, err)
|
require.Error(t, ErrMessageIsRequest, err)
|
||||||
})
|
})
|
||||||
t.Run("handle full sync response, no error", func(t *testing.T) {
|
t.Run("handle full sync response, no error", func(t *testing.T) {
|
||||||
|
@ -177,7 +181,44 @@ func TestSyncAclHandler_HandleMessage(t *testing.T) {
|
||||||
fx.aclMock.EXPECT().Id().AnyTimes().Return(fx.aclId)
|
fx.aclMock.EXPECT().Id().AnyTimes().Return(fx.aclId)
|
||||||
fx.syncProtocolMock.EXPECT().FullSyncResponse(ctx, fx.senderId, gomock.Any()).Return(nil)
|
fx.syncProtocolMock.EXPECT().FullSyncResponse(ctx, fx.senderId, gomock.Any()).Return(nil)
|
||||||
|
|
||||||
err := fx.syncHandler.HandleMessage(ctx, fx.senderId, objectMsg)
|
err := fx.syncHandler.HandleMessage(ctx, fx.senderId, 0, objectMsg)
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
t.Run("handle full sync response, new protocol, not equal heads", func(t *testing.T) {
|
||||||
|
fx := newSyncHandlerFixture(t)
|
||||||
|
defer fx.stop()
|
||||||
|
chWithId := &consensusproto.RawRecordWithId{}
|
||||||
|
fullResponse := &consensusproto.LogFullSyncResponse{
|
||||||
|
Head: "h1",
|
||||||
|
Records: []*consensusproto.RawRecordWithId{chWithId},
|
||||||
|
}
|
||||||
|
logMessage := consensusproto.WrapFullResponse(fullResponse, chWithId)
|
||||||
|
objectMsg, _ := spacesyncproto.MarshallSyncMessage(logMessage, fx.spaceId, fx.aclId)
|
||||||
|
|
||||||
|
fx.aclMock.EXPECT().Id().AnyTimes().Return(fx.aclId)
|
||||||
|
fx.aclMock.EXPECT().Head().AnyTimes().Return(&list.AclRecord{Id: "h2"})
|
||||||
|
fx.syncProtocolMock.EXPECT().FullSyncResponse(ctx, fx.senderId, gomock.Any()).Return(nil)
|
||||||
|
req := &consensusproto.LogSyncMessage{}
|
||||||
|
fx.syncClientMock.EXPECT().CreateFullSyncRequest(fx.aclMock, "h1").Return(req, nil)
|
||||||
|
fx.syncClientMock.EXPECT().QueueRequest(fx.senderId, req).Return(nil)
|
||||||
|
err := fx.syncHandler.HandleMessage(ctx, fx.senderId, secureservice.NewSyncProtoVersion, objectMsg)
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
t.Run("handle full sync response, new protocol, equal heads", func(t *testing.T) {
|
||||||
|
fx := newSyncHandlerFixture(t)
|
||||||
|
defer fx.stop()
|
||||||
|
chWithId := &consensusproto.RawRecordWithId{}
|
||||||
|
fullResponse := &consensusproto.LogFullSyncResponse{
|
||||||
|
Head: "h1",
|
||||||
|
Records: []*consensusproto.RawRecordWithId{chWithId},
|
||||||
|
}
|
||||||
|
logMessage := consensusproto.WrapFullResponse(fullResponse, chWithId)
|
||||||
|
objectMsg, _ := spacesyncproto.MarshallSyncMessage(logMessage, fx.spaceId, fx.aclId)
|
||||||
|
|
||||||
|
fx.aclMock.EXPECT().Id().AnyTimes().Return(fx.aclId)
|
||||||
|
fx.aclMock.EXPECT().Head().AnyTimes().Return(&list.AclRecord{Id: "h1"})
|
||||||
|
fx.syncProtocolMock.EXPECT().FullSyncResponse(ctx, fx.senderId, gomock.Any()).Return(nil)
|
||||||
|
err := fx.syncHandler.HandleMessage(ctx, fx.senderId, secureservice.NewSyncProtoVersion, objectMsg)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
package exporter
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/anyproto/any-sync/commonspace/object/acl/list"
|
|
||||||
"github.com/anyproto/any-sync/commonspace/object/acl/liststorage"
|
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
|
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
|
|
||||||
)
|
|
||||||
|
|
||||||
type TreeImportParams struct {
|
|
||||||
ListStorage liststorage.ListStorage
|
|
||||||
TreeStorage treestorage.TreeStorage
|
|
||||||
BeforeId string
|
|
||||||
IncludeBeforeId bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func ImportHistoryTree(params TreeImportParams) (tree objecttree.ReadableObjectTree, err error) {
|
|
||||||
aclList, err := list.BuildAclList(params.ListStorage, list.NoOpAcceptorVerifier{})
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return objecttree.BuildNonVerifiableHistoryTree(objecttree.HistoryTreeParams{
|
|
||||||
TreeStorage: params.TreeStorage,
|
|
||||||
AclList: aclList,
|
|
||||||
BeforeId: params.BeforeId,
|
|
||||||
IncludeBeforeId: params.IncludeBeforeId,
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -27,34 +27,46 @@ func (h *historyTree) rebuildFromStorage(params HistoryTreeParams) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *historyTree) rebuild(params HistoryTreeParams) (err error) {
|
func (h *historyTree) rebuild(params HistoryTreeParams) (err error) {
|
||||||
var (
|
|
||||||
beforeId = params.BeforeId
|
|
||||||
include = params.IncludeBeforeId
|
|
||||||
full = params.BuildFullTree
|
|
||||||
)
|
|
||||||
h.treeBuilder.Reset()
|
h.treeBuilder.Reset()
|
||||||
if full {
|
|
||||||
|
if len(params.Heads) == 0 {
|
||||||
h.tree, err = h.treeBuilder.BuildFull()
|
h.tree, err = h.treeBuilder.BuildFull()
|
||||||
return
|
return err
|
||||||
}
|
|
||||||
if beforeId == h.Id() && !include {
|
|
||||||
return ErrLoadBeforeRoot
|
|
||||||
}
|
}
|
||||||
|
|
||||||
heads := []string{beforeId}
|
if len(params.Heads) == 1 {
|
||||||
if beforeId == "" {
|
return h.rebuildWithSingleHead(params.IncludeBeforeId, params.Heads[0])
|
||||||
heads, err = h.treeStorage.Heads()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else if !include {
|
|
||||||
beforeChange, err := h.treeBuilder.loadChange(beforeId)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
heads = beforeChange.PreviousIds
|
|
||||||
}
|
}
|
||||||
|
|
||||||
h.tree, err = h.treeBuilder.build(heads, nil, nil)
|
h.tree, err = h.treeBuilder.build(params.Heads, nil, nil)
|
||||||
return
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *historyTree) rebuildWithSingleHead(includeBeforeId bool, head string) (err error) {
|
||||||
|
if head == "" {
|
||||||
|
return h.rebuildWithEmptyHead()
|
||||||
|
}
|
||||||
|
if !includeBeforeId {
|
||||||
|
return h.rebuildWithPreviousHead(head)
|
||||||
|
}
|
||||||
|
h.tree, err = h.treeBuilder.build([]string{head}, nil, nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *historyTree) rebuildWithEmptyHead() (err error) {
|
||||||
|
heads, err := h.treeStorage.Heads()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.tree, err = h.treeBuilder.build(heads, nil, nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *historyTree) rebuildWithPreviousHead(head string) (err error) {
|
||||||
|
change, err := h.treeBuilder.loadChange(head)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.tree, err = h.treeBuilder.build(change.PreviousIds, nil, nil)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1245,7 +1245,7 @@ func TestObjectTree(t *testing.T) {
|
||||||
}
|
}
|
||||||
deps.treeStorage.AddRawChangesSetHeads(rawChanges, []string{"6"})
|
deps.treeStorage.AddRawChangesSetHeads(rawChanges, []string{"6"})
|
||||||
hTree, err := buildHistoryTree(deps, HistoryTreeParams{
|
hTree, err := buildHistoryTree(deps, HistoryTreeParams{
|
||||||
BeforeId: "6",
|
Heads: []string{"6"},
|
||||||
IncludeBeforeId: false,
|
IncludeBeforeId: false,
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -1276,9 +1276,7 @@ func TestObjectTree(t *testing.T) {
|
||||||
changeCreator.CreateRaw("6", aclList.Head().Id, "5", false, "5"),
|
changeCreator.CreateRaw("6", aclList.Head().Id, "5", false, "5"),
|
||||||
}
|
}
|
||||||
deps.treeStorage.AddRawChangesSetHeads(rawChanges, []string{"6"})
|
deps.treeStorage.AddRawChangesSetHeads(rawChanges, []string{"6"})
|
||||||
hTree, err := buildHistoryTree(deps, HistoryTreeParams{
|
hTree, err := buildHistoryTree(deps, HistoryTreeParams{})
|
||||||
BuildFullTree: true,
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
// check tree heads
|
// check tree heads
|
||||||
assert.Equal(t, []string{"6"}, hTree.Heads())
|
assert.Equal(t, []string{"6"}, hTree.Heads())
|
||||||
|
@ -1307,8 +1305,7 @@ func TestObjectTree(t *testing.T) {
|
||||||
}
|
}
|
||||||
deps.treeStorage.AddRawChangesSetHeads(rawChanges, []string{"6"})
|
deps.treeStorage.AddRawChangesSetHeads(rawChanges, []string{"6"})
|
||||||
hTree, err := buildHistoryTree(deps, HistoryTreeParams{
|
hTree, err := buildHistoryTree(deps, HistoryTreeParams{
|
||||||
BeforeId: "6",
|
Heads: []string{"6"}, IncludeBeforeId: true,
|
||||||
IncludeBeforeId: true,
|
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
// check tree heads
|
// check tree heads
|
||||||
|
@ -1328,7 +1325,7 @@ func TestObjectTree(t *testing.T) {
|
||||||
t.Run("test history tree root", func(t *testing.T) {
|
t.Run("test history tree root", func(t *testing.T) {
|
||||||
_, deps := prepareHistoryTreeDeps(aclList)
|
_, deps := prepareHistoryTreeDeps(aclList)
|
||||||
hTree, err := buildHistoryTree(deps, HistoryTreeParams{
|
hTree, err := buildHistoryTree(deps, HistoryTreeParams{
|
||||||
BeforeId: "0",
|
Heads: []string{"0"},
|
||||||
IncludeBeforeId: true,
|
IncludeBeforeId: true,
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
|
@ -27,9 +27,8 @@ type ObjectTreeDerivePayload struct {
|
||||||
type HistoryTreeParams struct {
|
type HistoryTreeParams struct {
|
||||||
TreeStorage treestorage.TreeStorage
|
TreeStorage treestorage.TreeStorage
|
||||||
AclList list.AclList
|
AclList list.AclList
|
||||||
BeforeId string
|
Heads []string
|
||||||
IncludeBeforeId bool
|
IncludeBeforeId bool
|
||||||
BuildFullTree bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type objectTreeDeps struct {
|
type objectTreeDeps struct {
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
treechangeproto "github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
|
treechangeproto "github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
|
||||||
treestorage "github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
|
treestorage "github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
|
||||||
spacesyncproto "github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
spacesyncproto "github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
||||||
|
peer "github.com/anyproto/any-sync/net/peer"
|
||||||
gomock "go.uber.org/mock/gomock"
|
gomock "go.uber.org/mock/gomock"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -105,6 +106,21 @@ func (mr *MockSyncTreeMockRecorder) AddRawChanges(arg0, arg1 any) *gomock.Call {
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRawChanges", reflect.TypeOf((*MockSyncTree)(nil).AddRawChanges), arg0, arg1)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRawChanges", reflect.TypeOf((*MockSyncTree)(nil).AddRawChanges), arg0, arg1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddRawChangesFromPeer mocks base method.
|
||||||
|
func (m *MockSyncTree) AddRawChangesFromPeer(arg0 context.Context, arg1 string, arg2 objecttree.RawChangesPayload) (objecttree.AddResult, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "AddRawChangesFromPeer", arg0, arg1, arg2)
|
||||||
|
ret0, _ := ret[0].(objecttree.AddResult)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddRawChangesFromPeer indicates an expected call of AddRawChangesFromPeer.
|
||||||
|
func (mr *MockSyncTreeMockRecorder) AddRawChangesFromPeer(arg0, arg1, arg2 any) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRawChangesFromPeer", reflect.TypeOf((*MockSyncTree)(nil).AddRawChangesFromPeer), arg0, arg1, arg2)
|
||||||
|
}
|
||||||
|
|
||||||
// ChangeInfo mocks base method.
|
// ChangeInfo mocks base method.
|
||||||
func (m *MockSyncTree) ChangeInfo() *treechangeproto.TreeChangeInfo {
|
func (m *MockSyncTree) ChangeInfo() *treechangeproto.TreeChangeInfo {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
@ -207,17 +223,17 @@ func (mr *MockSyncTreeMockRecorder) GetChange(arg0 any) *gomock.Call {
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleMessage mocks base method.
|
// HandleMessage mocks base method.
|
||||||
func (m *MockSyncTree) HandleMessage(arg0 context.Context, arg1 string, arg2 *spacesyncproto.ObjectSyncMessage) error {
|
func (m *MockSyncTree) HandleMessage(arg0 context.Context, arg1 string, arg2 uint32, arg3 *spacesyncproto.ObjectSyncMessage) error {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "HandleMessage", arg0, arg1, arg2)
|
ret := m.ctrl.Call(m, "HandleMessage", arg0, arg1, arg2, arg3)
|
||||||
ret0, _ := ret[0].(error)
|
ret0, _ := ret[0].(error)
|
||||||
return ret0
|
return ret0
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleMessage indicates an expected call of HandleMessage.
|
// HandleMessage indicates an expected call of HandleMessage.
|
||||||
func (mr *MockSyncTreeMockRecorder) HandleMessage(arg0, arg1, arg2 any) *gomock.Call {
|
func (mr *MockSyncTreeMockRecorder) HandleMessage(arg0, arg1, arg2, arg3 any) *gomock.Call {
|
||||||
mr.mock.ctrl.T.Helper()
|
mr.mock.ctrl.T.Helper()
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleMessage", reflect.TypeOf((*MockSyncTree)(nil).HandleMessage), arg0, arg1, arg2)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleMessage", reflect.TypeOf((*MockSyncTree)(nil).HandleMessage), arg0, arg1, arg2, arg3)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleRequest mocks base method.
|
// HandleRequest mocks base method.
|
||||||
|
@ -445,7 +461,7 @@ func (mr *MockSyncTreeMockRecorder) Storage() *gomock.Call {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SyncWithPeer mocks base method.
|
// SyncWithPeer mocks base method.
|
||||||
func (m *MockSyncTree) SyncWithPeer(arg0 context.Context, arg1 string) error {
|
func (m *MockSyncTree) SyncWithPeer(arg0 context.Context, arg1 peer.Peer) error {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "SyncWithPeer", arg0, arg1)
|
ret := m.ctrl.Call(m, "SyncWithPeer", arg0, arg1)
|
||||||
ret0, _ := ret[0].(error)
|
ret0, _ := ret[0].(error)
|
||||||
|
@ -663,6 +679,20 @@ func (mr *MockSyncClientMockRecorder) Broadcast(arg0 any) *gomock.Call {
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Broadcast", reflect.TypeOf((*MockSyncClient)(nil).Broadcast), arg0)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Broadcast", reflect.TypeOf((*MockSyncClient)(nil).Broadcast), arg0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateEmptyFullSyncRequest mocks base method.
|
||||||
|
func (m *MockSyncClient) CreateEmptyFullSyncRequest(arg0 objecttree.ObjectTree) *treechangeproto.TreeSyncMessage {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "CreateEmptyFullSyncRequest", arg0)
|
||||||
|
ret0, _ := ret[0].(*treechangeproto.TreeSyncMessage)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateEmptyFullSyncRequest indicates an expected call of CreateEmptyFullSyncRequest.
|
||||||
|
func (mr *MockSyncClientMockRecorder) CreateEmptyFullSyncRequest(arg0 any) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateEmptyFullSyncRequest", reflect.TypeOf((*MockSyncClient)(nil).CreateEmptyFullSyncRequest), arg0)
|
||||||
|
}
|
||||||
|
|
||||||
// CreateFullSyncRequest mocks base method.
|
// CreateFullSyncRequest mocks base method.
|
||||||
func (m *MockSyncClient) CreateFullSyncRequest(arg0 objecttree.ObjectTree, arg1, arg2 []string) (*treechangeproto.TreeSyncMessage, error) {
|
func (m *MockSyncClient) CreateFullSyncRequest(arg0 objecttree.ObjectTree, arg1, arg2 []string) (*treechangeproto.TreeSyncMessage, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
@ -787,6 +817,20 @@ func (m *MockRequestFactory) EXPECT() *MockRequestFactoryMockRecorder {
|
||||||
return m.recorder
|
return m.recorder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateEmptyFullSyncRequest mocks base method.
|
||||||
|
func (m *MockRequestFactory) CreateEmptyFullSyncRequest(arg0 objecttree.ObjectTree) *treechangeproto.TreeSyncMessage {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "CreateEmptyFullSyncRequest", arg0)
|
||||||
|
ret0, _ := ret[0].(*treechangeproto.TreeSyncMessage)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateEmptyFullSyncRequest indicates an expected call of CreateEmptyFullSyncRequest.
|
||||||
|
func (mr *MockRequestFactoryMockRecorder) CreateEmptyFullSyncRequest(arg0 any) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateEmptyFullSyncRequest", reflect.TypeOf((*MockRequestFactory)(nil).CreateEmptyFullSyncRequest), arg0)
|
||||||
|
}
|
||||||
|
|
||||||
// CreateFullSyncRequest mocks base method.
|
// CreateFullSyncRequest mocks base method.
|
||||||
func (m *MockRequestFactory) CreateFullSyncRequest(arg0 objecttree.ObjectTree, arg1, arg2 []string) (*treechangeproto.TreeSyncMessage, error) {
|
func (m *MockRequestFactory) CreateFullSyncRequest(arg0 objecttree.ObjectTree, arg1, arg2 []string) (*treechangeproto.TreeSyncMessage, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
@ -898,16 +942,16 @@ func (mr *MockTreeSyncProtocolMockRecorder) FullSyncResponse(arg0, arg1, arg2 an
|
||||||
}
|
}
|
||||||
|
|
||||||
// HeadUpdate mocks base method.
|
// HeadUpdate mocks base method.
|
||||||
func (m *MockTreeSyncProtocol) HeadUpdate(arg0 context.Context, arg1 string, arg2 *treechangeproto.TreeHeadUpdate) (*treechangeproto.TreeSyncMessage, error) {
|
func (m *MockTreeSyncProtocol) HeadUpdate(arg0 context.Context, arg1 string, arg2 uint32, arg3 *treechangeproto.TreeHeadUpdate) (*treechangeproto.TreeSyncMessage, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "HeadUpdate", arg0, arg1, arg2)
|
ret := m.ctrl.Call(m, "HeadUpdate", arg0, arg1, arg2, arg3)
|
||||||
ret0, _ := ret[0].(*treechangeproto.TreeSyncMessage)
|
ret0, _ := ret[0].(*treechangeproto.TreeSyncMessage)
|
||||||
ret1, _ := ret[1].(error)
|
ret1, _ := ret[1].(error)
|
||||||
return ret0, ret1
|
return ret0, ret1
|
||||||
}
|
}
|
||||||
|
|
||||||
// HeadUpdate indicates an expected call of HeadUpdate.
|
// HeadUpdate indicates an expected call of HeadUpdate.
|
||||||
func (mr *MockTreeSyncProtocolMockRecorder) HeadUpdate(arg0, arg1, arg2 any) *gomock.Call {
|
func (mr *MockTreeSyncProtocolMockRecorder) HeadUpdate(arg0, arg1, arg2, arg3 any) *gomock.Call {
|
||||||
mr.mock.ctrl.T.Helper()
|
mr.mock.ctrl.T.Helper()
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeadUpdate", reflect.TypeOf((*MockTreeSyncProtocol)(nil).HeadUpdate), arg0, arg1, arg2)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeadUpdate", reflect.TypeOf((*MockTreeSyncProtocol)(nil).HeadUpdate), arg0, arg1, arg2, arg3)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package synctree
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
|
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
|
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
|
||||||
"github.com/anyproto/any-sync/util/slice"
|
"github.com/anyproto/any-sync/util/slice"
|
||||||
|
@ -10,6 +11,7 @@ import (
|
||||||
type RequestFactory interface {
|
type RequestFactory interface {
|
||||||
CreateHeadUpdate(t objecttree.ObjectTree, added []*treechangeproto.RawTreeChangeWithId) (msg *treechangeproto.TreeSyncMessage)
|
CreateHeadUpdate(t objecttree.ObjectTree, added []*treechangeproto.RawTreeChangeWithId) (msg *treechangeproto.TreeSyncMessage)
|
||||||
CreateNewTreeRequest() (msg *treechangeproto.TreeSyncMessage)
|
CreateNewTreeRequest() (msg *treechangeproto.TreeSyncMessage)
|
||||||
|
CreateEmptyFullSyncRequest(t objecttree.ObjectTree) (req *treechangeproto.TreeSyncMessage)
|
||||||
CreateFullSyncRequest(t objecttree.ObjectTree, theirHeads, theirSnapshotPath []string) (req *treechangeproto.TreeSyncMessage, err error)
|
CreateFullSyncRequest(t objecttree.ObjectTree, theirHeads, theirSnapshotPath []string) (req *treechangeproto.TreeSyncMessage, err error)
|
||||||
CreateFullSyncResponse(t objecttree.ObjectTree, theirHeads, theirSnapshotPath []string) (*treechangeproto.TreeSyncMessage, error)
|
CreateFullSyncResponse(t objecttree.ObjectTree, theirHeads, theirSnapshotPath []string) (*treechangeproto.TreeSyncMessage, error)
|
||||||
}
|
}
|
||||||
|
@ -32,6 +34,13 @@ func (r *requestFactory) CreateNewTreeRequest() (msg *treechangeproto.TreeSyncMe
|
||||||
return treechangeproto.WrapFullRequest(&treechangeproto.TreeFullSyncRequest{}, nil)
|
return treechangeproto.WrapFullRequest(&treechangeproto.TreeFullSyncRequest{}, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *requestFactory) CreateEmptyFullSyncRequest(t objecttree.ObjectTree) (msg *treechangeproto.TreeSyncMessage) {
|
||||||
|
return treechangeproto.WrapFullRequest(&treechangeproto.TreeFullSyncRequest{
|
||||||
|
Heads: t.Heads(),
|
||||||
|
SnapshotPath: t.SnapshotPath(),
|
||||||
|
}, t.Header())
|
||||||
|
}
|
||||||
|
|
||||||
func (r *requestFactory) CreateFullSyncRequest(t objecttree.ObjectTree, theirHeads, theirSnapshotPath []string) (msg *treechangeproto.TreeSyncMessage, err error) {
|
func (r *requestFactory) CreateFullSyncRequest(t objecttree.ObjectTree, theirHeads, theirSnapshotPath []string) (msg *treechangeproto.TreeSyncMessage, err error) {
|
||||||
req := &treechangeproto.TreeFullSyncRequest{}
|
req := &treechangeproto.TreeFullSyncRequest{}
|
||||||
if t == nil {
|
if t == nil {
|
||||||
|
|
|
@ -4,6 +4,7 @@ package synctree
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"slices"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
@ -18,7 +19,9 @@ import (
|
||||||
"github.com/anyproto/any-sync/commonspace/spacestorage"
|
"github.com/anyproto/any-sync/commonspace/spacestorage"
|
||||||
"github.com/anyproto/any-sync/commonspace/syncstatus"
|
"github.com/anyproto/any-sync/commonspace/syncstatus"
|
||||||
"github.com/anyproto/any-sync/net/peer"
|
"github.com/anyproto/any-sync/net/peer"
|
||||||
|
"github.com/anyproto/any-sync/net/secureservice"
|
||||||
"github.com/anyproto/any-sync/nodeconf"
|
"github.com/anyproto/any-sync/nodeconf"
|
||||||
|
"github.com/anyproto/any-sync/util/slice"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -34,11 +37,16 @@ type ListenerSetter interface {
|
||||||
SetListener(listener updatelistener.UpdateListener)
|
SetListener(listener updatelistener.UpdateListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
type SyncTree interface {
|
type peerSendableObjectTree interface {
|
||||||
objecttree.ObjectTree
|
objecttree.ObjectTree
|
||||||
|
AddRawChangesFromPeer(ctx context.Context, peerId string, changesPayload objecttree.RawChangesPayload) (res objecttree.AddResult, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type SyncTree interface {
|
||||||
|
peerSendableObjectTree
|
||||||
synchandler.SyncHandler
|
synchandler.SyncHandler
|
||||||
ListenerSetter
|
ListenerSetter
|
||||||
SyncWithPeer(ctx context.Context, peerId string) (err error)
|
SyncWithPeer(ctx context.Context, p peer.Peer) (err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SyncTree sends head updates to sync service and also sends new changes to update listener
|
// SyncTree sends head updates to sync service and also sends new changes to update listener
|
||||||
|
@ -79,13 +87,13 @@ type BuildDeps struct {
|
||||||
func BuildSyncTreeOrGetRemote(ctx context.Context, id string, deps BuildDeps) (t SyncTree, err error) {
|
func BuildSyncTreeOrGetRemote(ctx context.Context, id string, deps BuildDeps) (t SyncTree, err error) {
|
||||||
var (
|
var (
|
||||||
remoteGetter = treeRemoteGetter{treeId: id, deps: deps}
|
remoteGetter = treeRemoteGetter{treeId: id, deps: deps}
|
||||||
isRemote bool
|
peerId string
|
||||||
)
|
)
|
||||||
deps.TreeStorage, isRemote, err = remoteGetter.getTree(ctx)
|
deps.TreeStorage, peerId, err = remoteGetter.getTree(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return buildSyncTree(ctx, isRemote, deps)
|
return buildSyncTree(ctx, peerId, deps)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PutSyncTree(ctx context.Context, payload treestorage.TreeStorageCreatePayload, deps BuildDeps) (t SyncTree, err error) {
|
func PutSyncTree(ctx context.Context, payload treestorage.TreeStorageCreatePayload, deps BuildDeps) (t SyncTree, err error) {
|
||||||
|
@ -93,10 +101,10 @@ func PutSyncTree(ctx context.Context, payload treestorage.TreeStorageCreatePaylo
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return buildSyncTree(ctx, true, deps)
|
return buildSyncTree(ctx, peer.CtxResponsiblePeers, deps)
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildSyncTree(ctx context.Context, sendUpdate bool, deps BuildDeps) (t SyncTree, err error) {
|
func buildSyncTree(ctx context.Context, peerId string, deps BuildDeps) (t SyncTree, err error) {
|
||||||
objTree, err := deps.BuildObjectTree(deps.TreeStorage, deps.AclList)
|
objTree, err := deps.BuildObjectTree(deps.TreeStorage, deps.AclList)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -118,10 +126,13 @@ func buildSyncTree(ctx context.Context, sendUpdate bool, deps BuildDeps) (t Sync
|
||||||
syncTree.Unlock()
|
syncTree.Unlock()
|
||||||
|
|
||||||
// don't send updates for empty derived trees, because they won't be accepted
|
// don't send updates for empty derived trees, because they won't be accepted
|
||||||
if sendUpdate && !objecttree.IsEmptyDerivedTree(objTree) {
|
if peerId != "" && !objecttree.IsEmptyDerivedTree(objTree) {
|
||||||
headUpdate := syncTree.syncClient.CreateHeadUpdate(t, nil)
|
headUpdate := syncTree.syncClient.CreateHeadUpdate(t, nil)
|
||||||
// send to everybody, because everybody should know that the node or client got new tree
|
// send to everybody, because everybody should know that the node or client got new tree
|
||||||
syncTree.syncClient.Broadcast(headUpdate)
|
syncTree.syncClient.Broadcast(headUpdate)
|
||||||
|
if peerId != peer.CtxResponsiblePeers {
|
||||||
|
deps.SyncStatus.ObjectReceive(peerId, syncTree.Id(), syncTree.Heads())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -166,6 +177,38 @@ func (s *syncTree) AddContentWithValidator(ctx context.Context, content objecttr
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *syncTree) hasHeads(ot objecttree.ObjectTree, heads []string) bool {
|
||||||
|
return slice.UnsortedEquals(ot.Heads(), heads) || ot.HasChanges(heads...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *syncTree) AddRawChangesFromPeer(ctx context.Context, peerId string, changesPayload objecttree.RawChangesPayload) (res objecttree.AddResult, err error) {
|
||||||
|
if s.hasHeads(s, changesPayload.NewHeads) {
|
||||||
|
s.syncStatus.HeadsApply(peerId, s.Id(), s.Heads(), true)
|
||||||
|
return objecttree.AddResult{
|
||||||
|
OldHeads: changesPayload.NewHeads,
|
||||||
|
Heads: changesPayload.NewHeads,
|
||||||
|
Mode: objecttree.Nothing,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
prevHeads := s.Heads()
|
||||||
|
res, err = s.AddRawChanges(ctx, changesPayload)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
curHeads := s.Heads()
|
||||||
|
allAdded := true
|
||||||
|
for _, head := range changesPayload.NewHeads {
|
||||||
|
if !slices.Contains(curHeads, head) {
|
||||||
|
allAdded = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !slice.UnsortedEquals(prevHeads, curHeads) {
|
||||||
|
s.syncStatus.HeadsApply(peerId, s.Id(), curHeads, allAdded)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (s *syncTree) AddRawChanges(ctx context.Context, changesPayload objecttree.RawChangesPayload) (res objecttree.AddResult, err error) {
|
func (s *syncTree) AddRawChanges(ctx context.Context, changesPayload objecttree.RawChangesPayload) (res objecttree.AddResult, err error) {
|
||||||
if err = s.checkAlive(); err != nil {
|
if err = s.checkAlive(); err != nil {
|
||||||
return
|
return
|
||||||
|
@ -251,14 +294,21 @@ func (s *syncTree) checkAlive() (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *syncTree) SyncWithPeer(ctx context.Context, peerId string) (err error) {
|
func (s *syncTree) SyncWithPeer(ctx context.Context, p peer.Peer) (err error) {
|
||||||
s.Lock()
|
s.Lock()
|
||||||
defer s.Unlock()
|
defer s.Unlock()
|
||||||
if objecttree.IsEmptyDerivedTree(s) {
|
if objecttree.IsEmptyDerivedTree(s.ObjectTree) {
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
headUpdate := s.syncClient.CreateHeadUpdate(s, nil)
|
protoVersion, err := peer.CtxProtoVersion(p.Context())
|
||||||
return s.syncClient.SendUpdate(peerId, headUpdate.RootChange.Id, headUpdate)
|
// this works with old protocol
|
||||||
|
if err != nil || protoVersion <= secureservice.ProtoVersion {
|
||||||
|
headUpdate := s.syncClient.CreateHeadUpdate(s, nil)
|
||||||
|
return s.syncClient.SendUpdate(p.Id(), headUpdate.RootChange.Id, headUpdate)
|
||||||
|
}
|
||||||
|
// for new protocol sending empty request
|
||||||
|
request := s.syncClient.CreateEmptyFullSyncRequest(s)
|
||||||
|
return s.syncClient.QueueRequest(p.Id(), s.Id(), request)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *syncTree) afterBuild() {
|
func (s *syncTree) afterBuild() {
|
||||||
|
|
|
@ -60,7 +60,7 @@ func Test_BuildSyncTree(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
headUpdate := &treechangeproto.TreeSyncMessage{}
|
headUpdate := &treechangeproto.TreeSyncMessage{}
|
||||||
t.Run("AddRawChanges update", func(t *testing.T) {
|
t.Run("AddRawChangesFromPeer update", func(t *testing.T) {
|
||||||
changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}}
|
changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}}
|
||||||
payload := objecttree.RawChangesPayload{
|
payload := objecttree.RawChangesPayload{
|
||||||
NewHeads: nil,
|
NewHeads: nil,
|
||||||
|
@ -70,6 +70,8 @@ func Test_BuildSyncTree(t *testing.T) {
|
||||||
Added: changes,
|
Added: changes,
|
||||||
Mode: objecttree.Append,
|
Mode: objecttree.Append,
|
||||||
}
|
}
|
||||||
|
objTreeMock.EXPECT().Heads().AnyTimes().Return([]string{"headId"})
|
||||||
|
objTreeMock.EXPECT().HasChanges(gomock.Any()).AnyTimes().Return(false)
|
||||||
objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(payload)).
|
objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(payload)).
|
||||||
Return(expectedRes, nil)
|
Return(expectedRes, nil)
|
||||||
updateListenerMock.EXPECT().Update(tr)
|
updateListenerMock.EXPECT().Update(tr)
|
||||||
|
@ -77,12 +79,12 @@ func Test_BuildSyncTree(t *testing.T) {
|
||||||
syncClientMock.EXPECT().CreateHeadUpdate(gomock.Eq(tr), gomock.Eq(changes)).Return(headUpdate)
|
syncClientMock.EXPECT().CreateHeadUpdate(gomock.Eq(tr), gomock.Eq(changes)).Return(headUpdate)
|
||||||
syncClientMock.EXPECT().Broadcast(gomock.Eq(headUpdate))
|
syncClientMock.EXPECT().Broadcast(gomock.Eq(headUpdate))
|
||||||
objTreeMock.EXPECT().Flush()
|
objTreeMock.EXPECT().Flush()
|
||||||
res, err := tr.AddRawChanges(ctx, payload)
|
res, err := tr.AddRawChangesFromPeer(ctx, "peerId", payload)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, expectedRes, res)
|
require.Equal(t, expectedRes, res)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("AddRawChanges rebuild", func(t *testing.T) {
|
t.Run("AddRawChangesFromPeer rebuild", func(t *testing.T) {
|
||||||
changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}}
|
changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}}
|
||||||
payload := objecttree.RawChangesPayload{
|
payload := objecttree.RawChangesPayload{
|
||||||
NewHeads: nil,
|
NewHeads: nil,
|
||||||
|
@ -93,6 +95,7 @@ func Test_BuildSyncTree(t *testing.T) {
|
||||||
Added: changes,
|
Added: changes,
|
||||||
Mode: objecttree.Rebuild,
|
Mode: objecttree.Rebuild,
|
||||||
}
|
}
|
||||||
|
objTreeMock.EXPECT().Heads().AnyTimes().Return([]string{"headId"})
|
||||||
objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(payload)).
|
objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(payload)).
|
||||||
Return(expectedRes, nil)
|
Return(expectedRes, nil)
|
||||||
updateListenerMock.EXPECT().Rebuild(tr)
|
updateListenerMock.EXPECT().Rebuild(tr)
|
||||||
|
@ -100,12 +103,12 @@ func Test_BuildSyncTree(t *testing.T) {
|
||||||
syncClientMock.EXPECT().CreateHeadUpdate(gomock.Eq(tr), gomock.Eq(changes)).Return(headUpdate)
|
syncClientMock.EXPECT().CreateHeadUpdate(gomock.Eq(tr), gomock.Eq(changes)).Return(headUpdate)
|
||||||
syncClientMock.EXPECT().Broadcast(gomock.Eq(headUpdate))
|
syncClientMock.EXPECT().Broadcast(gomock.Eq(headUpdate))
|
||||||
objTreeMock.EXPECT().Flush()
|
objTreeMock.EXPECT().Flush()
|
||||||
res, err := tr.AddRawChanges(ctx, payload)
|
res, err := tr.AddRawChangesFromPeer(ctx, "peerId", payload)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, expectedRes, res)
|
require.Equal(t, expectedRes, res)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("AddRawChanges nothing", func(t *testing.T) {
|
t.Run("AddRawChangesFromPeer nothing", func(t *testing.T) {
|
||||||
changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}}
|
changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}}
|
||||||
payload := objecttree.RawChangesPayload{
|
payload := objecttree.RawChangesPayload{
|
||||||
NewHeads: nil,
|
NewHeads: nil,
|
||||||
|
@ -115,10 +118,11 @@ func Test_BuildSyncTree(t *testing.T) {
|
||||||
Added: changes,
|
Added: changes,
|
||||||
Mode: objecttree.Nothing,
|
Mode: objecttree.Nothing,
|
||||||
}
|
}
|
||||||
|
objTreeMock.EXPECT().Heads().AnyTimes().Return([]string{"headId"})
|
||||||
objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(payload)).
|
objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(payload)).
|
||||||
Return(expectedRes, nil)
|
Return(expectedRes, nil)
|
||||||
|
|
||||||
res, err := tr.AddRawChanges(ctx, payload)
|
res, err := tr.AddRawChangesFromPeer(ctx, "peerId", payload)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, expectedRes, res)
|
require.Equal(t, expectedRes, res)
|
||||||
})
|
})
|
||||||
|
|
|
@ -5,13 +5,15 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/gogo/protobuf/proto"
|
||||||
|
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
|
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
|
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
|
||||||
"github.com/anyproto/any-sync/commonspace/objectsync/synchandler"
|
"github.com/anyproto/any-sync/commonspace/objectsync/synchandler"
|
||||||
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
||||||
"github.com/anyproto/any-sync/commonspace/syncstatus"
|
"github.com/anyproto/any-sync/commonspace/syncstatus"
|
||||||
|
"github.com/anyproto/any-sync/net/secureservice"
|
||||||
"github.com/anyproto/any-sync/util/slice"
|
"github.com/anyproto/any-sync/util/slice"
|
||||||
"github.com/gogo/protobuf/proto"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -34,10 +36,10 @@ type syncTreeHandler struct {
|
||||||
|
|
||||||
const maxQueueSize = 5
|
const maxQueueSize = 5
|
||||||
|
|
||||||
func newSyncTreeHandler(spaceId string, objTree objecttree.ObjectTree, syncClient SyncClient, syncStatus syncstatus.StatusUpdater) synchandler.SyncHandler {
|
func newSyncTreeHandler(spaceId string, objTree peerSendableObjectTree, syncClient SyncClient, syncStatus syncstatus.StatusUpdater) synchandler.SyncHandler {
|
||||||
return &syncTreeHandler{
|
return &syncTreeHandler{
|
||||||
objTree: objTree,
|
objTree: objTree,
|
||||||
syncProtocol: newTreeSyncProtocol(spaceId, objTree, syncClient),
|
syncProtocol: newTreeSyncProtocol(spaceId, objTree, syncClient, syncStatus),
|
||||||
syncClient: syncClient,
|
syncClient: syncClient,
|
||||||
syncStatus: syncStatus,
|
syncStatus: syncStatus,
|
||||||
spaceId: spaceId,
|
spaceId: spaceId,
|
||||||
|
@ -85,7 +87,7 @@ func (s *syncTreeHandler) handleRequest(ctx context.Context, senderId string, fu
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *syncTreeHandler) HandleMessage(ctx context.Context, senderId string, msg *spacesyncproto.ObjectSyncMessage) (err error) {
|
func (s *syncTreeHandler) HandleMessage(ctx context.Context, senderId string, protoVersion uint32, msg *spacesyncproto.ObjectSyncMessage) (err error) {
|
||||||
unmarshalled := &treechangeproto.TreeSyncMessage{}
|
unmarshalled := &treechangeproto.TreeSyncMessage{}
|
||||||
err = proto.Unmarshal(msg.Payload, unmarshalled)
|
err = proto.Unmarshal(msg.Payload, unmarshalled)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -100,10 +102,10 @@ func (s *syncTreeHandler) HandleMessage(ctx context.Context, senderId string, ms
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.handlerLock.Unlock()
|
s.handlerLock.Unlock()
|
||||||
return s.handleMessage(ctx, unmarshalled, senderId)
|
return s.handleMessage(ctx, unmarshalled, protoVersion, senderId)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *syncTreeHandler) handleMessage(ctx context.Context, msg *treechangeproto.TreeSyncMessage, senderId string) (err error) {
|
func (s *syncTreeHandler) handleMessage(ctx context.Context, msg *treechangeproto.TreeSyncMessage, protoVersion uint32, senderId string) (err error) {
|
||||||
s.objTree.Lock()
|
s.objTree.Lock()
|
||||||
defer s.objTree.Unlock()
|
defer s.objTree.Unlock()
|
||||||
var (
|
var (
|
||||||
|
@ -129,7 +131,7 @@ func (s *syncTreeHandler) handleMessage(ctx context.Context, msg *treechangeprot
|
||||||
switch {
|
switch {
|
||||||
case content.GetHeadUpdate() != nil:
|
case content.GetHeadUpdate() != nil:
|
||||||
var syncReq *treechangeproto.TreeSyncMessage
|
var syncReq *treechangeproto.TreeSyncMessage
|
||||||
syncReq, err = s.syncProtocol.HeadUpdate(ctx, senderId, content.GetHeadUpdate())
|
syncReq, err = s.syncProtocol.HeadUpdate(ctx, senderId, protoVersion, content.GetHeadUpdate())
|
||||||
if err != nil || syncReq == nil {
|
if err != nil || syncReq == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -137,7 +139,27 @@ func (s *syncTreeHandler) handleMessage(ctx context.Context, msg *treechangeprot
|
||||||
case content.GetFullSyncRequest() != nil:
|
case content.GetFullSyncRequest() != nil:
|
||||||
return ErrMessageIsRequest
|
return ErrMessageIsRequest
|
||||||
case content.GetFullSyncResponse() != nil:
|
case content.GetFullSyncResponse() != nil:
|
||||||
return s.syncProtocol.FullSyncResponse(ctx, senderId, content.GetFullSyncResponse())
|
err := s.syncProtocol.FullSyncResponse(ctx, senderId, content.GetFullSyncResponse())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cnt := content.GetFullSyncResponse()
|
||||||
|
if protoVersion <= secureservice.ProtoVersion || slice.UnsortedEquals(cnt.Heads, s.objTree.Heads()) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
req, err := s.syncClient.CreateFullSyncRequest(s.objTree, cnt.Heads, cnt.SnapshotPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return s.syncClient.QueueRequest(senderId, treeId, req)
|
||||||
|
default:
|
||||||
|
if protoVersion <= secureservice.ProtoVersion {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
req, err := s.syncClient.CreateFullSyncRequest(s.objTree, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return s.syncClient.QueueRequest(senderId, treeId, req)
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,13 +5,16 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"go.uber.org/mock/gomock"
|
||||||
|
|
||||||
|
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree/mock_objecttree"
|
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree/mock_objecttree"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/synctree/mock_synctree"
|
"github.com/anyproto/any-sync/commonspace/object/tree/synctree/mock_synctree"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
|
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
|
||||||
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
||||||
"github.com/anyproto/any-sync/commonspace/syncstatus"
|
"github.com/anyproto/any-sync/commonspace/syncstatus"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/anyproto/any-sync/net/secureservice"
|
||||||
"go.uber.org/mock/gomock"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type testObjTreeMock struct {
|
type testObjTreeMock struct {
|
||||||
|
@ -19,6 +22,10 @@ type testObjTreeMock struct {
|
||||||
m sync.RWMutex
|
m sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *testObjTreeMock) AddRawChangesFromPeer(ctx context.Context, peerId string, changesPayload objecttree.RawChangesPayload) (res objecttree.AddResult, err error) {
|
||||||
|
return t.MockObjectTree.AddRawChanges(ctx, changesPayload)
|
||||||
|
}
|
||||||
|
|
||||||
func newTestObjMock(mockTree *mock_objecttree.MockObjectTree) *testObjTreeMock {
|
func newTestObjMock(mockTree *mock_objecttree.MockObjectTree) *testObjTreeMock {
|
||||||
return &testObjTreeMock{
|
return &testObjTreeMock{
|
||||||
MockObjectTree: mockTree,
|
MockObjectTree: mockTree,
|
||||||
|
@ -111,10 +118,10 @@ func TestSyncTreeHandler_HandleMessage(t *testing.T) {
|
||||||
fx.objectTreeMock.EXPECT().Id().AnyTimes().Return(fx.treeId)
|
fx.objectTreeMock.EXPECT().Id().AnyTimes().Return(fx.treeId)
|
||||||
fx.objectTreeMock.EXPECT().Heads().Times(2).Return([]string{"h2"})
|
fx.objectTreeMock.EXPECT().Heads().Times(2).Return([]string{"h2"})
|
||||||
fx.objectTreeMock.EXPECT().Heads().Times(2).Return([]string{"h3"})
|
fx.objectTreeMock.EXPECT().Heads().Times(2).Return([]string{"h3"})
|
||||||
fx.syncProtocolMock.EXPECT().HeadUpdate(ctx, fx.senderId, gomock.Any()).Return(syncReq, nil)
|
fx.syncProtocolMock.EXPECT().HeadUpdate(ctx, fx.senderId, uint32(0), gomock.Any()).Return(syncReq, nil)
|
||||||
fx.syncClientMock.EXPECT().QueueRequest(fx.senderId, fx.treeId, syncReq).Return(nil)
|
fx.syncClientMock.EXPECT().QueueRequest(fx.senderId, fx.treeId, syncReq).Return(nil)
|
||||||
|
|
||||||
err := fx.syncHandler.HandleMessage(ctx, fx.senderId, objectMsg)
|
err := fx.syncHandler.HandleMessage(ctx, fx.senderId, 0, objectMsg)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, []string{"h3"}, fx.syncHandler.heads)
|
require.Equal(t, []string{"h3"}, fx.syncHandler.heads)
|
||||||
})
|
})
|
||||||
|
@ -133,7 +140,7 @@ func TestSyncTreeHandler_HandleMessage(t *testing.T) {
|
||||||
fx.syncHandler.heads = []string{"h1"}
|
fx.syncHandler.heads = []string{"h1"}
|
||||||
fx.objectTreeMock.EXPECT().Id().AnyTimes().Return(fx.treeId)
|
fx.objectTreeMock.EXPECT().Id().AnyTimes().Return(fx.treeId)
|
||||||
|
|
||||||
err := fx.syncHandler.HandleMessage(ctx, fx.senderId, objectMsg)
|
err := fx.syncHandler.HandleMessage(ctx, fx.senderId, 0, objectMsg)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -152,9 +159,9 @@ func TestSyncTreeHandler_HandleMessage(t *testing.T) {
|
||||||
fx.objectTreeMock.EXPECT().Id().AnyTimes().Return(fx.treeId)
|
fx.objectTreeMock.EXPECT().Id().AnyTimes().Return(fx.treeId)
|
||||||
fx.objectTreeMock.EXPECT().Heads().Times(2).Return([]string{"h2"})
|
fx.objectTreeMock.EXPECT().Heads().Times(2).Return([]string{"h2"})
|
||||||
fx.objectTreeMock.EXPECT().Heads().Times(2).Return([]string{"h3"})
|
fx.objectTreeMock.EXPECT().Heads().Times(2).Return([]string{"h3"})
|
||||||
fx.syncProtocolMock.EXPECT().HeadUpdate(ctx, fx.senderId, gomock.Any()).Return(nil, nil)
|
fx.syncProtocolMock.EXPECT().HeadUpdate(ctx, fx.senderId, uint32(0), gomock.Any()).Return(nil, nil)
|
||||||
|
|
||||||
err := fx.syncHandler.HandleMessage(ctx, fx.senderId, objectMsg)
|
err := fx.syncHandler.HandleMessage(ctx, fx.senderId, 0, objectMsg)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, []string{"h3"}, fx.syncHandler.heads)
|
require.Equal(t, []string{"h3"}, fx.syncHandler.heads)
|
||||||
})
|
})
|
||||||
|
@ -174,7 +181,7 @@ func TestSyncTreeHandler_HandleMessage(t *testing.T) {
|
||||||
fx.objectTreeMock.EXPECT().Id().AnyTimes().Return(fx.treeId)
|
fx.objectTreeMock.EXPECT().Id().AnyTimes().Return(fx.treeId)
|
||||||
fx.objectTreeMock.EXPECT().Heads().Times(3).Return([]string{"h2"})
|
fx.objectTreeMock.EXPECT().Heads().Times(3).Return([]string{"h2"})
|
||||||
|
|
||||||
err := fx.syncHandler.HandleMessage(ctx, fx.senderId, objectMsg)
|
err := fx.syncHandler.HandleMessage(ctx, fx.senderId, 0, objectMsg)
|
||||||
require.Equal(t, err, ErrMessageIsRequest)
|
require.Equal(t, err, ErrMessageIsRequest)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -195,7 +202,66 @@ func TestSyncTreeHandler_HandleMessage(t *testing.T) {
|
||||||
fx.objectTreeMock.EXPECT().Heads().Times(2).Return([]string{"h3"})
|
fx.objectTreeMock.EXPECT().Heads().Times(2).Return([]string{"h3"})
|
||||||
fx.syncProtocolMock.EXPECT().FullSyncResponse(ctx, fx.senderId, gomock.Any()).Return(nil)
|
fx.syncProtocolMock.EXPECT().FullSyncResponse(ctx, fx.senderId, gomock.Any()).Return(nil)
|
||||||
|
|
||||||
err := fx.syncHandler.HandleMessage(ctx, fx.senderId, objectMsg)
|
err := fx.syncHandler.HandleMessage(ctx, fx.senderId, 0, objectMsg)
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("handle full sync response new protocol heads not equal", func(t *testing.T) {
|
||||||
|
fx := newSyncHandlerFixture(t)
|
||||||
|
defer fx.stop()
|
||||||
|
treeId := "treeId"
|
||||||
|
chWithId := &treechangeproto.RawTreeChangeWithId{}
|
||||||
|
fullSyncResponse := &treechangeproto.TreeFullSyncResponse{
|
||||||
|
Heads: []string{"h3"},
|
||||||
|
SnapshotPath: []string{"h3"},
|
||||||
|
}
|
||||||
|
treeMsg := treechangeproto.WrapFullResponse(fullSyncResponse, chWithId)
|
||||||
|
objectMsg, _ := spacesyncproto.MarshallSyncMessage(treeMsg, "spaceId", treeId)
|
||||||
|
|
||||||
|
fx.syncHandler.heads = []string{"h2"}
|
||||||
|
fx.objectTreeMock.EXPECT().Id().AnyTimes().Return(fx.treeId)
|
||||||
|
fx.objectTreeMock.EXPECT().Heads().AnyTimes().Return([]string{"h2"})
|
||||||
|
fx.syncProtocolMock.EXPECT().FullSyncResponse(ctx, fx.senderId, gomock.Any()).Return(nil)
|
||||||
|
req := &treechangeproto.TreeSyncMessage{}
|
||||||
|
fx.syncClientMock.EXPECT().CreateFullSyncRequest(fx.objectTreeMock, fullSyncResponse.Heads, fullSyncResponse.SnapshotPath).Return(req, nil)
|
||||||
|
fx.syncClientMock.EXPECT().QueueRequest(fx.senderId, fx.treeId, req).Return(nil)
|
||||||
|
err := fx.syncHandler.HandleMessage(ctx, fx.senderId, secureservice.NewSyncProtoVersion, objectMsg)
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("handle full sync response new protocol heads equal", func(t *testing.T) {
|
||||||
|
fx := newSyncHandlerFixture(t)
|
||||||
|
defer fx.stop()
|
||||||
|
treeId := "treeId"
|
||||||
|
chWithId := &treechangeproto.RawTreeChangeWithId{}
|
||||||
|
fullSyncResponse := &treechangeproto.TreeFullSyncResponse{
|
||||||
|
Heads: []string{"h3"},
|
||||||
|
SnapshotPath: []string{"h3"},
|
||||||
|
}
|
||||||
|
treeMsg := treechangeproto.WrapFullResponse(fullSyncResponse, chWithId)
|
||||||
|
objectMsg, _ := spacesyncproto.MarshallSyncMessage(treeMsg, "spaceId", treeId)
|
||||||
|
|
||||||
|
fx.syncHandler.heads = []string{"h2"}
|
||||||
|
fx.objectTreeMock.EXPECT().Id().AnyTimes().Return(fx.treeId)
|
||||||
|
fx.objectTreeMock.EXPECT().Heads().Times(2).Return([]string{"h2"})
|
||||||
|
fx.objectTreeMock.EXPECT().Heads().Times(3).Return([]string{"h3"})
|
||||||
|
fx.syncProtocolMock.EXPECT().FullSyncResponse(ctx, fx.senderId, gomock.Any()).Return(nil)
|
||||||
|
err := fx.syncHandler.HandleMessage(ctx, fx.senderId, secureservice.NewSyncProtoVersion, objectMsg)
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("handle full sync response new protocol empty message", func(t *testing.T) {
|
||||||
|
fx := newSyncHandlerFixture(t)
|
||||||
|
defer fx.stop()
|
||||||
|
treeId := "treeId"
|
||||||
|
objectMsg := &spacesyncproto.ObjectSyncMessage{ObjectId: treeId}
|
||||||
|
fx.syncHandler.heads = []string{"h2"}
|
||||||
|
fx.objectTreeMock.EXPECT().Id().AnyTimes().Return(fx.treeId)
|
||||||
|
fx.objectTreeMock.EXPECT().Heads().AnyTimes().Return([]string{"h2"})
|
||||||
|
req := &treechangeproto.TreeSyncMessage{}
|
||||||
|
fx.syncClientMock.EXPECT().CreateFullSyncRequest(fx.objectTreeMock, nil, nil).Return(req, nil)
|
||||||
|
fx.syncClientMock.EXPECT().QueueRequest(fx.senderId, fx.treeId, req).Return(nil)
|
||||||
|
err := fx.syncHandler.HandleMessage(ctx, fx.senderId, secureservice.NewSyncProtoVersion, objectMsg)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,16 +60,20 @@ func (t treeRemoteGetter) treeRequest(ctx context.Context, peerId string) (msg *
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t treeRemoteGetter) treeRequestLoop(ctx context.Context) (msg *treechangeproto.TreeSyncMessage, err error) {
|
func (t treeRemoteGetter) treeRequestLoop(ctx context.Context) (msg *treechangeproto.TreeSyncMessage, peerId string, err error) {
|
||||||
availablePeers, err := t.getPeers(ctx)
|
availablePeers, err := t.getPeers(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// in future we will try to load from different peers
|
// in future we will try to load from different peers
|
||||||
return t.treeRequest(ctx, availablePeers[0])
|
res, err := t.treeRequest(ctx, availablePeers[0])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return res, availablePeers[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t treeRemoteGetter) getTree(ctx context.Context) (treeStorage treestorage.TreeStorage, isRemote bool, err error) {
|
func (t treeRemoteGetter) getTree(ctx context.Context) (treeStorage treestorage.TreeStorage, peerId string, err error) {
|
||||||
treeStorage, err = t.deps.SpaceStorage.TreeStorage(t.treeId)
|
treeStorage, err = t.deps.SpaceStorage.TreeStorage(t.treeId)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return
|
return
|
||||||
|
@ -87,8 +91,7 @@ func (t treeRemoteGetter) getTree(ctx context.Context) (treeStorage treestorage.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
isRemote = true
|
resp, peerId, err := t.treeRequestLoop(ctx)
|
||||||
resp, err := t.treeRequestLoop(ctx)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ func TestTreeRemoteGetter(t *testing.T) {
|
||||||
fx.peerGetterMock.EXPECT().GetResponsiblePeers(tCtx).Return([]peer.Peer{mockPeer}, nil)
|
fx.peerGetterMock.EXPECT().GetResponsiblePeers(tCtx).Return([]peer.Peer{mockPeer}, nil)
|
||||||
fx.syncClientMock.EXPECT().CreateNewTreeRequest().Return(treeRequest)
|
fx.syncClientMock.EXPECT().CreateNewTreeRequest().Return(treeRequest)
|
||||||
fx.syncClientMock.EXPECT().SendRequest(tCtx, peerId, fx.treeGetter.treeId, treeRequest).Return(objectResponse, nil)
|
fx.syncClientMock.EXPECT().SendRequest(tCtx, peerId, fx.treeGetter.treeId, treeRequest).Return(objectResponse, nil)
|
||||||
resp, err := fx.treeGetter.treeRequestLoop(tCtx)
|
resp, _, err := fx.treeGetter.treeRequestLoop(tCtx)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, "id", resp.RootChange.Id)
|
require.Equal(t, "id", resp.RootChange.Id)
|
||||||
})
|
})
|
||||||
|
@ -84,7 +84,7 @@ func TestTreeRemoteGetter(t *testing.T) {
|
||||||
mockPeer.EXPECT().Id().AnyTimes().Return(peerId)
|
mockPeer.EXPECT().Id().AnyTimes().Return(peerId)
|
||||||
fx.syncClientMock.EXPECT().CreateNewTreeRequest().Return(treeRequest)
|
fx.syncClientMock.EXPECT().CreateNewTreeRequest().Return(treeRequest)
|
||||||
fx.syncClientMock.EXPECT().SendRequest(tCtx, peerId, fx.treeGetter.treeId, treeRequest).AnyTimes().Return(nil, fmt.Errorf("some"))
|
fx.syncClientMock.EXPECT().SendRequest(tCtx, peerId, fx.treeGetter.treeId, treeRequest).AnyTimes().Return(nil, fmt.Errorf("some"))
|
||||||
_, err := fx.treeGetter.treeRequestLoop(tCtx)
|
_, _, err := fx.treeGetter.treeRequestLoop(tCtx)
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,15 +3,18 @@ package synctree
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
|
|
||||||
"github.com/anyproto/any-sync/app/logger"
|
"github.com/anyproto/any-sync/app/logger"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
|
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
|
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
|
||||||
|
"github.com/anyproto/any-sync/commonspace/syncstatus"
|
||||||
|
"github.com/anyproto/any-sync/net/secureservice"
|
||||||
"github.com/anyproto/any-sync/util/slice"
|
"github.com/anyproto/any-sync/util/slice"
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type TreeSyncProtocol interface {
|
type TreeSyncProtocol interface {
|
||||||
HeadUpdate(ctx context.Context, senderId string, update *treechangeproto.TreeHeadUpdate) (request *treechangeproto.TreeSyncMessage, err error)
|
HeadUpdate(ctx context.Context, senderId string, protoVersion uint32, update *treechangeproto.TreeHeadUpdate) (request *treechangeproto.TreeSyncMessage, err error)
|
||||||
FullSyncRequest(ctx context.Context, senderId string, request *treechangeproto.TreeFullSyncRequest) (response *treechangeproto.TreeSyncMessage, err error)
|
FullSyncRequest(ctx context.Context, senderId string, request *treechangeproto.TreeFullSyncRequest) (response *treechangeproto.TreeSyncMessage, err error)
|
||||||
FullSyncResponse(ctx context.Context, senderId string, response *treechangeproto.TreeFullSyncResponse) (err error)
|
FullSyncResponse(ctx context.Context, senderId string, response *treechangeproto.TreeFullSyncResponse) (err error)
|
||||||
}
|
}
|
||||||
|
@ -19,20 +22,22 @@ type TreeSyncProtocol interface {
|
||||||
type treeSyncProtocol struct {
|
type treeSyncProtocol struct {
|
||||||
log logger.CtxLogger
|
log logger.CtxLogger
|
||||||
spaceId string
|
spaceId string
|
||||||
objTree objecttree.ObjectTree
|
objTree peerSendableObjectTree
|
||||||
|
syncStatus syncstatus.StatusUpdater
|
||||||
reqFactory RequestFactory
|
reqFactory RequestFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTreeSyncProtocol(spaceId string, objTree objecttree.ObjectTree, reqFactory RequestFactory) *treeSyncProtocol {
|
func newTreeSyncProtocol(spaceId string, objTree peerSendableObjectTree, reqFactory RequestFactory, syncStatus syncstatus.StatusUpdater) *treeSyncProtocol {
|
||||||
return &treeSyncProtocol{
|
return &treeSyncProtocol{
|
||||||
log: log.With(zap.String("spaceId", spaceId), zap.String("treeId", objTree.Id())),
|
log: log.With(zap.String("spaceId", spaceId), zap.String("treeId", objTree.Id())),
|
||||||
spaceId: spaceId,
|
spaceId: spaceId,
|
||||||
objTree: objTree,
|
objTree: objTree,
|
||||||
|
syncStatus: syncStatus,
|
||||||
reqFactory: reqFactory,
|
reqFactory: reqFactory,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *treeSyncProtocol) HeadUpdate(ctx context.Context, senderId string, update *treechangeproto.TreeHeadUpdate) (fullRequest *treechangeproto.TreeSyncMessage, err error) {
|
func (t *treeSyncProtocol) HeadUpdate(ctx context.Context, senderId string, protoVersion uint32, update *treechangeproto.TreeHeadUpdate) (fullRequest *treechangeproto.TreeSyncMessage, err error) {
|
||||||
var (
|
var (
|
||||||
isEmptyUpdate = len(update.Changes) == 0
|
isEmptyUpdate = len(update.Changes) == 0
|
||||||
objTree = t.objTree
|
objTree = t.objTree
|
||||||
|
@ -62,6 +67,9 @@ func (t *treeSyncProtocol) HeadUpdate(ctx context.Context, senderId string, upda
|
||||||
headEquals := slice.UnsortedEquals(objTree.Heads(), update.Heads)
|
headEquals := slice.UnsortedEquals(objTree.Heads(), update.Heads)
|
||||||
log.DebugCtx(ctx, "is empty update", zap.Bool("headEquals", headEquals))
|
log.DebugCtx(ctx, "is empty update", zap.Bool("headEquals", headEquals))
|
||||||
if headEquals {
|
if headEquals {
|
||||||
|
if protoVersion > secureservice.ProtoVersion {
|
||||||
|
t.syncStatus.HeadsApply(senderId, objTree.Id(), update.Heads, true)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,11 +78,7 @@ func (t *treeSyncProtocol) HeadUpdate(ctx context.Context, senderId string, upda
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.hasHeads(objTree, update.Heads) {
|
_, err = objTree.AddRawChangesFromPeer(ctx, senderId, objecttree.RawChangesPayload{
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = objTree.AddRawChanges(ctx, objecttree.RawChangesPayload{
|
|
||||||
NewHeads: update.Heads,
|
NewHeads: update.Heads,
|
||||||
RawChanges: update.Changes,
|
RawChanges: update.Changes,
|
||||||
})
|
})
|
||||||
|
@ -109,8 +113,8 @@ func (t *treeSyncProtocol) FullSyncRequest(ctx context.Context, senderId string,
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if len(request.Changes) != 0 && !t.hasHeads(objTree, request.Heads) {
|
if len(request.Changes) != 0 {
|
||||||
_, err = objTree.AddRawChanges(ctx, objecttree.RawChangesPayload{
|
_, err = objTree.AddRawChangesFromPeer(ctx, senderId, objecttree.RawChangesPayload{
|
||||||
NewHeads: request.Heads,
|
NewHeads: request.Heads,
|
||||||
RawChanges: request.Changes,
|
RawChanges: request.Changes,
|
||||||
})
|
})
|
||||||
|
@ -137,11 +141,8 @@ func (t *treeSyncProtocol) FullSyncResponse(ctx context.Context, senderId string
|
||||||
log.DebugCtx(ctx, "full sync response succeeded")
|
log.DebugCtx(ctx, "full sync response succeeded")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
if t.hasHeads(objTree, response.Heads) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = objTree.AddRawChanges(ctx, objecttree.RawChangesPayload{
|
_, err = objTree.AddRawChangesFromPeer(ctx, senderId, objecttree.RawChangesPayload{
|
||||||
NewHeads: response.Heads,
|
NewHeads: response.Heads,
|
||||||
RawChanges: response.Changes,
|
RawChanges: response.Changes,
|
||||||
})
|
})
|
||||||
|
|
|
@ -3,14 +3,17 @@ package synctree
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"go.uber.org/mock/gomock"
|
||||||
|
|
||||||
"github.com/anyproto/any-sync/app/logger"
|
"github.com/anyproto/any-sync/app/logger"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
|
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree/mock_objecttree"
|
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree/mock_objecttree"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/synctree/mock_synctree"
|
"github.com/anyproto/any-sync/commonspace/object/tree/synctree/mock_synctree"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
|
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/anyproto/any-sync/commonspace/syncstatus"
|
||||||
"go.uber.org/mock/gomock"
|
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type treeSyncProtocolFixture struct {
|
type treeSyncProtocolFixture struct {
|
||||||
|
@ -32,7 +35,7 @@ func newSyncProtocolFixture(t *testing.T) *treeSyncProtocolFixture {
|
||||||
spaceId := "spaceId"
|
spaceId := "spaceId"
|
||||||
reqFactory := mock_synctree.NewMockRequestFactory(ctrl)
|
reqFactory := mock_synctree.NewMockRequestFactory(ctrl)
|
||||||
objTree.EXPECT().Id().Return("treeId")
|
objTree.EXPECT().Id().Return("treeId")
|
||||||
syncProtocol := newTreeSyncProtocol(spaceId, objTree, reqFactory)
|
syncProtocol := newTreeSyncProtocol(spaceId, objTree, reqFactory, syncstatus.NewNoOpSyncStatus())
|
||||||
return &treeSyncProtocolFixture{
|
return &treeSyncProtocolFixture{
|
||||||
log: log,
|
log: log,
|
||||||
spaceId: spaceId,
|
spaceId: spaceId,
|
||||||
|
@ -69,8 +72,7 @@ func TestTreeSyncProtocol_HeadUpdate(t *testing.T) {
|
||||||
SnapshotPath: []string{"h1"},
|
SnapshotPath: []string{"h1"},
|
||||||
}
|
}
|
||||||
fx.objectTreeMock.EXPECT().Id().AnyTimes().Return(fx.treeId)
|
fx.objectTreeMock.EXPECT().Id().AnyTimes().Return(fx.treeId)
|
||||||
fx.objectTreeMock.EXPECT().Heads().Return([]string{"h2"}).Times(2)
|
fx.objectTreeMock.EXPECT().Heads().Return([]string{"h2"}).AnyTimes()
|
||||||
fx.objectTreeMock.EXPECT().HasChanges(gomock.Eq([]string{"h1"})).Return(false)
|
|
||||||
fx.objectTreeMock.EXPECT().
|
fx.objectTreeMock.EXPECT().
|
||||||
AddRawChanges(gomock.Any(), gomock.Eq(objecttree.RawChangesPayload{
|
AddRawChanges(gomock.Any(), gomock.Eq(objecttree.RawChangesPayload{
|
||||||
NewHeads: []string{"h1"},
|
NewHeads: []string{"h1"},
|
||||||
|
@ -79,7 +81,7 @@ func TestTreeSyncProtocol_HeadUpdate(t *testing.T) {
|
||||||
Return(objecttree.AddResult{}, nil)
|
Return(objecttree.AddResult{}, nil)
|
||||||
fx.objectTreeMock.EXPECT().HasChanges(gomock.Eq([]string{"h1"})).Return(true)
|
fx.objectTreeMock.EXPECT().HasChanges(gomock.Eq([]string{"h1"})).Return(true)
|
||||||
|
|
||||||
res, err := fx.syncProtocol.HeadUpdate(ctx, fx.senderId, headUpdate)
|
res, err := fx.syncProtocol.HeadUpdate(ctx, fx.senderId, 0, headUpdate)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Nil(t, res)
|
require.Nil(t, res)
|
||||||
})
|
})
|
||||||
|
@ -96,8 +98,14 @@ func TestTreeSyncProtocol_HeadUpdate(t *testing.T) {
|
||||||
|
|
||||||
fx.objectTreeMock.EXPECT().Id().AnyTimes().Return(fx.treeId)
|
fx.objectTreeMock.EXPECT().Id().AnyTimes().Return(fx.treeId)
|
||||||
fx.objectTreeMock.EXPECT().Heads().Return([]string{"h1"}).AnyTimes()
|
fx.objectTreeMock.EXPECT().Heads().Return([]string{"h1"}).AnyTimes()
|
||||||
|
fx.objectTreeMock.EXPECT().
|
||||||
|
AddRawChanges(gomock.Any(), gomock.Eq(objecttree.RawChangesPayload{
|
||||||
|
NewHeads: []string{"h1"},
|
||||||
|
RawChanges: []*treechangeproto.RawTreeChangeWithId{chWithId},
|
||||||
|
})).
|
||||||
|
Return(objecttree.AddResult{}, nil)
|
||||||
|
|
||||||
res, err := fx.syncProtocol.HeadUpdate(ctx, fx.senderId, headUpdate)
|
res, err := fx.syncProtocol.HeadUpdate(ctx, fx.senderId, 0, headUpdate)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Nil(t, res)
|
require.Nil(t, res)
|
||||||
})
|
})
|
||||||
|
@ -117,7 +125,7 @@ func TestTreeSyncProtocol_HeadUpdate(t *testing.T) {
|
||||||
CreateFullSyncRequest(gomock.Eq(fx.objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"})).
|
CreateFullSyncRequest(gomock.Eq(fx.objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"})).
|
||||||
Return(fullRequest, nil)
|
Return(fullRequest, nil)
|
||||||
|
|
||||||
res, err := fx.syncProtocol.HeadUpdate(ctx, fx.senderId, headUpdate)
|
res, err := fx.syncProtocol.HeadUpdate(ctx, fx.senderId, 0, headUpdate)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, fullRequest, res)
|
require.Equal(t, fullRequest, res)
|
||||||
})
|
})
|
||||||
|
@ -134,7 +142,7 @@ func TestTreeSyncProtocol_HeadUpdate(t *testing.T) {
|
||||||
fx.objectTreeMock.EXPECT().Id().AnyTimes().Return(fx.treeId)
|
fx.objectTreeMock.EXPECT().Id().AnyTimes().Return(fx.treeId)
|
||||||
fx.objectTreeMock.EXPECT().Heads().Return([]string{"h1"}).AnyTimes()
|
fx.objectTreeMock.EXPECT().Heads().Return([]string{"h1"}).AnyTimes()
|
||||||
|
|
||||||
res, err := fx.syncProtocol.HeadUpdate(ctx, fx.senderId, headUpdate)
|
res, err := fx.syncProtocol.HeadUpdate(ctx, fx.senderId, 0, headUpdate)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Nil(t, res)
|
require.Nil(t, res)
|
||||||
})
|
})
|
||||||
|
@ -161,7 +169,7 @@ func TestTreeSyncProtocol_FullSyncRequest(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fx.objectTreeMock.EXPECT().Heads().Return([]string{"h2"}).AnyTimes()
|
fx.objectTreeMock.EXPECT().Heads().Return([]string{"h2"}).AnyTimes()
|
||||||
fx.objectTreeMock.EXPECT().HasChanges(gomock.Eq([]string{"h1"})).Return(false)
|
fx.objectTreeMock.EXPECT().HasChanges(gomock.Eq([]string{"h1"})).AnyTimes().Return(false)
|
||||||
fx.objectTreeMock.EXPECT().
|
fx.objectTreeMock.EXPECT().
|
||||||
AddRawChanges(gomock.Any(), gomock.Eq(objecttree.RawChangesPayload{
|
AddRawChanges(gomock.Any(), gomock.Eq(objecttree.RawChangesPayload{
|
||||||
NewHeads: []string{"h1"},
|
NewHeads: []string{"h1"},
|
||||||
|
@ -190,6 +198,12 @@ func TestTreeSyncProtocol_FullSyncRequest(t *testing.T) {
|
||||||
fx.objectTreeMock.EXPECT().
|
fx.objectTreeMock.EXPECT().
|
||||||
Heads().
|
Heads().
|
||||||
Return([]string{"h1"}).AnyTimes()
|
Return([]string{"h1"}).AnyTimes()
|
||||||
|
fx.objectTreeMock.EXPECT().
|
||||||
|
AddRawChanges(gomock.Any(), gomock.Eq(objecttree.RawChangesPayload{
|
||||||
|
NewHeads: []string{"h1"},
|
||||||
|
RawChanges: []*treechangeproto.RawTreeChangeWithId{chWithId},
|
||||||
|
})).
|
||||||
|
Return(objecttree.AddResult{}, nil)
|
||||||
fx.reqFactory.EXPECT().
|
fx.reqFactory.EXPECT().
|
||||||
CreateFullSyncResponse(gomock.Eq(fx.objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"})).
|
CreateFullSyncResponse(gomock.Eq(fx.objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"})).
|
||||||
Return(fullResponse, nil)
|
Return(fullResponse, nil)
|
||||||
|
@ -228,7 +242,6 @@ func TestTreeSyncProtocol_FullSyncRequest(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fx.objectTreeMock.EXPECT().Heads().Return([]string{"h2"}).AnyTimes()
|
fx.objectTreeMock.EXPECT().Heads().Return([]string{"h2"}).AnyTimes()
|
||||||
fx.objectTreeMock.EXPECT().HasChanges(gomock.Eq([]string{"h1"})).Return(false)
|
|
||||||
fx.objectTreeMock.EXPECT().
|
fx.objectTreeMock.EXPECT().
|
||||||
AddRawChanges(gomock.Any(), gomock.Eq(objecttree.RawChangesPayload{
|
AddRawChanges(gomock.Any(), gomock.Eq(objecttree.RawChangesPayload{
|
||||||
NewHeads: []string{"h1"},
|
NewHeads: []string{"h1"},
|
||||||
|
@ -258,9 +271,6 @@ func TestTreeSyncProtocol_FullSyncResponse(t *testing.T) {
|
||||||
fx.objectTreeMock.EXPECT().
|
fx.objectTreeMock.EXPECT().
|
||||||
Heads().
|
Heads().
|
||||||
Return([]string{"h2"}).AnyTimes()
|
Return([]string{"h2"}).AnyTimes()
|
||||||
fx.objectTreeMock.EXPECT().
|
|
||||||
HasChanges(gomock.Eq([]string{"h1"})).
|
|
||||||
Return(false)
|
|
||||||
fx.objectTreeMock.EXPECT().
|
fx.objectTreeMock.EXPECT().
|
||||||
AddRawChanges(gomock.Any(), gomock.Eq(objecttree.RawChangesPayload{
|
AddRawChanges(gomock.Any(), gomock.Eq(objecttree.RawChangesPayload{
|
||||||
NewHeads: []string{"h1"},
|
NewHeads: []string{"h1"},
|
||||||
|
@ -286,6 +296,12 @@ func TestTreeSyncProtocol_FullSyncResponse(t *testing.T) {
|
||||||
fx.objectTreeMock.EXPECT().
|
fx.objectTreeMock.EXPECT().
|
||||||
Heads().
|
Heads().
|
||||||
Return([]string{"h1"}).AnyTimes()
|
Return([]string{"h1"}).AnyTimes()
|
||||||
|
fx.objectTreeMock.EXPECT().
|
||||||
|
AddRawChanges(gomock.Any(), gomock.Eq(objecttree.RawChangesPayload{
|
||||||
|
NewHeads: []string{"h1"},
|
||||||
|
RawChanges: []*treechangeproto.RawTreeChangeWithId{chWithId},
|
||||||
|
})).
|
||||||
|
Return(objecttree.AddResult{}, nil)
|
||||||
|
|
||||||
err := fx.syncProtocol.FullSyncResponse(ctx, fx.senderId, fullSyncResponse)
|
err := fx.syncProtocol.FullSyncResponse(ctx, fx.senderId, fullSyncResponse)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
|
@ -3,6 +3,16 @@ package synctree
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/cheggaaa/mb/v3"
|
||||||
|
"github.com/gogo/protobuf/proto"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
|
|
||||||
"github.com/anyproto/any-sync/app"
|
"github.com/anyproto/any-sync/app"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/acl/list"
|
"github.com/anyproto/any-sync/commonspace/object/acl/list"
|
||||||
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
|
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
|
||||||
|
@ -12,14 +22,6 @@ import (
|
||||||
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
||||||
"github.com/anyproto/any-sync/commonspace/syncstatus"
|
"github.com/anyproto/any-sync/commonspace/syncstatus"
|
||||||
"github.com/anyproto/any-sync/net/peer"
|
"github.com/anyproto/any-sync/net/peer"
|
||||||
"github.com/cheggaaa/mb/v3"
|
|
||||||
"github.com/gogo/protobuf/proto"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"golang.org/x/exp/slices"
|
|
||||||
"math/rand"
|
|
||||||
"sync"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// protocolMsg is a message used in sync protocol tests
|
// protocolMsg is a message used in sync protocol tests
|
||||||
|
@ -210,7 +212,7 @@ func createEmptySyncHandler(peerId, spaceId string, builder objecttree.BuildObje
|
||||||
|
|
||||||
func (h *testSyncHandler) HandleMessage(ctx context.Context, senderId string, request *spacesyncproto.ObjectSyncMessage) (err error) {
|
func (h *testSyncHandler) HandleMessage(ctx context.Context, senderId string, request *spacesyncproto.ObjectSyncMessage) (err error) {
|
||||||
if h.SyncHandler != nil {
|
if h.SyncHandler != nil {
|
||||||
return h.SyncHandler.HandleMessage(ctx, senderId, request)
|
return h.SyncHandler.HandleMessage(ctx, senderId, 0, request)
|
||||||
}
|
}
|
||||||
unmarshalled := &treechangeproto.TreeSyncMessage{}
|
unmarshalled := &treechangeproto.TreeSyncMessage{}
|
||||||
err = proto.Unmarshal(request.Payload, unmarshalled)
|
err = proto.Unmarshal(request.Payload, unmarshalled)
|
||||||
|
@ -317,6 +319,16 @@ func (b *broadcastTree) AddRawChanges(ctx context.Context, changes objecttree.Ra
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *broadcastTree) AddRawChangesFromPeer(ctx context.Context, peerId string, changes objecttree.RawChangesPayload) (objecttree.AddResult, error) {
|
||||||
|
res, err := b.ObjectTree.AddRawChanges(ctx, changes)
|
||||||
|
if err != nil {
|
||||||
|
return objecttree.AddResult{}, err
|
||||||
|
}
|
||||||
|
upd := b.SyncClient.CreateHeadUpdate(b.ObjectTree, res.Added)
|
||||||
|
b.SyncClient.Broadcast(upd)
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
func createStorage(treeId string, aclList list.AclList) treestorage.TreeStorage {
|
func createStorage(treeId string, aclList list.AclList) treestorage.TreeStorage {
|
||||||
changeCreator := objecttree.NewMockChangeCreator()
|
changeCreator := objecttree.NewMockChangeCreator()
|
||||||
st := changeCreator.CreateNewTreeStorage(treeId, aclList.Head().Id, false)
|
st := changeCreator.CreateNewTreeStorage(treeId, aclList.Head().Id, false)
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
|
|
||||||
app "github.com/anyproto/any-sync/app"
|
app "github.com/anyproto/any-sync/app"
|
||||||
|
peer "github.com/anyproto/any-sync/net/peer"
|
||||||
gomock "go.uber.org/mock/gomock"
|
gomock "go.uber.org/mock/gomock"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -135,7 +136,7 @@ func (mr *MockTreeSyncerMockRecorder) StopSync() *gomock.Call {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SyncAll mocks base method.
|
// SyncAll mocks base method.
|
||||||
func (m *MockTreeSyncer) SyncAll(arg0 context.Context, arg1 string, arg2, arg3 []string) error {
|
func (m *MockTreeSyncer) SyncAll(arg0 context.Context, arg1 peer.Peer, arg2, arg3 []string) error {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "SyncAll", arg0, arg1, arg2, arg3)
|
ret := m.ctrl.Call(m, "SyncAll", arg0, arg1, arg2, arg3)
|
||||||
ret0, _ := ret[0].(error)
|
ret0, _ := ret[0].(error)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/anyproto/any-sync/app"
|
"github.com/anyproto/any-sync/app"
|
||||||
|
"github.com/anyproto/any-sync/net/peer"
|
||||||
)
|
)
|
||||||
|
|
||||||
const CName = "common.object.treesyncer"
|
const CName = "common.object.treesyncer"
|
||||||
|
@ -14,5 +15,5 @@ type TreeSyncer interface {
|
||||||
StartSync()
|
StartSync()
|
||||||
StopSync()
|
StopSync()
|
||||||
ShouldSync(peerId string) bool
|
ShouldSync(peerId string) bool
|
||||||
SyncAll(ctx context.Context, peerId string, existing, missing []string) error
|
SyncAll(ctx context.Context, p peer.Peer, existing, missing []string) error
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"github.com/anyproto/any-sync/commonspace/spacestate"
|
"github.com/anyproto/any-sync/commonspace/spacestate"
|
||||||
"github.com/anyproto/any-sync/metric"
|
"github.com/anyproto/any-sync/metric"
|
||||||
"github.com/anyproto/any-sync/net/peer"
|
"github.com/anyproto/any-sync/net/peer"
|
||||||
|
"github.com/anyproto/any-sync/net/secureservice"
|
||||||
"github.com/anyproto/any-sync/util/multiqueue"
|
"github.com/anyproto/any-sync/util/multiqueue"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
@ -128,6 +129,10 @@ func (s *objectSync) HandleMessage(ctx context.Context, hm HandleMessage) (err e
|
||||||
|
|
||||||
func (s *objectSync) processHandleMessage(msg HandleMessage) {
|
func (s *objectSync) processHandleMessage(msg HandleMessage) {
|
||||||
var err error
|
var err error
|
||||||
|
peerProtoVersion, err := peer.CtxProtoVersion(msg.PeerCtx)
|
||||||
|
if err != nil {
|
||||||
|
peerProtoVersion = secureservice.ProtoVersion
|
||||||
|
}
|
||||||
msg.StartHandlingTime = time.Now()
|
msg.StartHandlingTime = time.Now()
|
||||||
ctx := peer.CtxWithPeerId(context.Background(), msg.SenderId)
|
ctx := peer.CtxWithPeerId(context.Background(), msg.SenderId)
|
||||||
ctx = logger.CtxWithFields(ctx, zap.Uint64("msgId", msg.Id), zap.String("senderId", msg.SenderId))
|
ctx = logger.CtxWithFields(ctx, zap.Uint64("msgId", msg.Id), zap.String("senderId", msg.SenderId))
|
||||||
|
@ -148,7 +153,7 @@ func (s *objectSync) processHandleMessage(msg HandleMessage) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err = s.handleMessage(ctx, msg.SenderId, msg.Message); err != nil {
|
if err = s.handleMessage(ctx, msg.SenderId, peerProtoVersion, msg.Message); err != nil {
|
||||||
if msg.Message.ObjectId != "" {
|
if msg.Message.ObjectId != "" {
|
||||||
// cleanup thread on error
|
// cleanup thread on error
|
||||||
_ = s.handleQueue.CloseThread(msg.Message.ObjectId)
|
_ = s.handleQueue.CloseThread(msg.Message.ObjectId)
|
||||||
|
@ -170,7 +175,7 @@ func (s *objectSync) handleRequest(ctx context.Context, senderId string, msg *sp
|
||||||
return obj.HandleRequest(ctx, senderId, msg)
|
return obj.HandleRequest(ctx, senderId, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *objectSync) handleMessage(ctx context.Context, senderId string, msg *spacesyncproto.ObjectSyncMessage) (err error) {
|
func (s *objectSync) handleMessage(ctx context.Context, senderId string, protoVersion uint32, msg *spacesyncproto.ObjectSyncMessage) (err error) {
|
||||||
log := log.With(zap.String("objectId", msg.ObjectId))
|
log := log.With(zap.String("objectId", msg.ObjectId))
|
||||||
defer func() {
|
defer func() {
|
||||||
if p := recover(); p != nil {
|
if p := recover(); p != nil {
|
||||||
|
@ -186,7 +191,7 @@ func (s *objectSync) handleMessage(ctx context.Context, senderId string, msg *sp
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get object from cache: %w", err)
|
return fmt.Errorf("failed to get object from cache: %w", err)
|
||||||
}
|
}
|
||||||
err = obj.HandleMessage(ctx, senderId, msg)
|
err = obj.HandleMessage(ctx, senderId, protoVersion, msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to handle message: %w", err)
|
return fmt.Errorf("failed to handle message: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,11 @@ package synchandler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SyncHandler interface {
|
type SyncHandler interface {
|
||||||
HandleMessage(ctx context.Context, senderId string, message *spacesyncproto.ObjectSyncMessage) (err error)
|
HandleMessage(ctx context.Context, senderId string, protoVersion uint32, message *spacesyncproto.ObjectSyncMessage) (err error)
|
||||||
HandleRequest(ctx context.Context, senderId string, request *spacesyncproto.ObjectSyncMessage) (response *spacesyncproto.ObjectSyncMessage, err error)
|
HandleRequest(ctx context.Context, senderId string, request *spacesyncproto.ObjectSyncMessage) (response *spacesyncproto.ObjectSyncMessage, err error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,9 +39,8 @@ var log = logger.NewNamed(CName)
|
||||||
var ErrSpaceClosed = errors.New("space is closed")
|
var ErrSpaceClosed = errors.New("space is closed")
|
||||||
|
|
||||||
type HistoryTreeOpts struct {
|
type HistoryTreeOpts struct {
|
||||||
BeforeId string
|
Heads []string
|
||||||
Include bool
|
Include bool
|
||||||
BuildFullTree bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type TreeBuilder interface {
|
type TreeBuilder interface {
|
||||||
|
@ -145,9 +144,8 @@ func (t *treeBuilder) BuildHistoryTree(ctx context.Context, id string, opts Hist
|
||||||
|
|
||||||
params := objecttree.HistoryTreeParams{
|
params := objecttree.HistoryTreeParams{
|
||||||
AclList: t.aclList,
|
AclList: t.aclList,
|
||||||
BeforeId: opts.BeforeId,
|
Heads: opts.Heads,
|
||||||
IncludeBeforeId: opts.Include,
|
IncludeBeforeId: opts.Include,
|
||||||
BuildFullTree: opts.BuildFullTree,
|
|
||||||
}
|
}
|
||||||
params.TreeStorage, err = t.spaceStorage.TreeStorage(id)
|
params.TreeStorage, err = t.spaceStorage.TreeStorage(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -13,7 +13,6 @@ import (
|
||||||
"github.com/anyproto/any-sync/commonspace/objectsync"
|
"github.com/anyproto/any-sync/commonspace/objectsync"
|
||||||
"github.com/anyproto/any-sync/commonspace/spacestate"
|
"github.com/anyproto/any-sync/commonspace/spacestate"
|
||||||
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
||||||
"github.com/anyproto/any-sync/net/peer"
|
|
||||||
"github.com/anyproto/any-sync/net/pool"
|
"github.com/anyproto/any-sync/net/pool"
|
||||||
"github.com/anyproto/any-sync/net/rpc/rpcerr"
|
"github.com/anyproto/any-sync/net/rpc/rpcerr"
|
||||||
)
|
)
|
||||||
|
@ -112,7 +111,11 @@ func (r *requestManager) SendRequest(ctx context.Context, peerId string, req *sp
|
||||||
defer func() {
|
defer func() {
|
||||||
r.reqStat.RemoveSyncRequest(peerId, req)
|
r.reqStat.RemoveSyncRequest(peerId, req)
|
||||||
}()
|
}()
|
||||||
return r.doRequest(ctx, peerId, req)
|
res, err := r.doRequest(ctx, peerId, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return res.resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *requestManager) QueueRequest(peerId string, req *spacesyncproto.ObjectSyncMessage) (err error) {
|
func (r *requestManager) QueueRequest(peerId string, req *spacesyncproto.ObjectSyncMessage) (err error) {
|
||||||
|
@ -142,27 +145,36 @@ var doRequestAndHandle = (*requestManager).requestAndHandle
|
||||||
|
|
||||||
func (r *requestManager) requestAndHandle(peerId string, req *spacesyncproto.ObjectSyncMessage) {
|
func (r *requestManager) requestAndHandle(peerId string, req *spacesyncproto.ObjectSyncMessage) {
|
||||||
ctx := r.ctx
|
ctx := r.ctx
|
||||||
resp, err := r.doRequest(ctx, peerId, req)
|
res, err := r.doRequest(ctx, peerId, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("failed to send request", zap.Error(err))
|
log.Warn("failed to send request", zap.Error(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx = peer.CtxWithPeerId(ctx, peerId)
|
|
||||||
_ = r.handler.HandleMessage(ctx, objectsync.HandleMessage{
|
_ = r.handler.HandleMessage(ctx, objectsync.HandleMessage{
|
||||||
SenderId: peerId,
|
SenderId: peerId,
|
||||||
Message: resp,
|
Message: res.resp,
|
||||||
PeerCtx: ctx,
|
PeerCtx: res.peerCtx,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *requestManager) doRequest(ctx context.Context, peerId string, msg *spacesyncproto.ObjectSyncMessage) (resp *spacesyncproto.ObjectSyncMessage, err error) {
|
type result struct {
|
||||||
|
peerCtx context.Context
|
||||||
|
resp *spacesyncproto.ObjectSyncMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *requestManager) doRequest(ctx context.Context, peerId string, msg *spacesyncproto.ObjectSyncMessage) (res result, err error) {
|
||||||
pr, err := r.peerPool.Get(ctx, peerId)
|
pr, err := r.peerPool.Get(ctx, peerId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
res.peerCtx = pr.Context()
|
||||||
err = pr.DoDrpc(ctx, func(conn drpc.Conn) error {
|
err = pr.DoDrpc(ctx, func(conn drpc.Conn) error {
|
||||||
cl := r.clientFactory.Client(conn)
|
cl := r.clientFactory.Client(conn)
|
||||||
resp, err = cl.ObjectSync(ctx, msg)
|
resp, err := cl.ObjectSync(ctx, msg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
res.resp = resp
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
err = rpcerr.Unwrap(err)
|
err = rpcerr.Unwrap(err)
|
||||||
|
|
|
@ -66,12 +66,14 @@ func TestRequestManager_SyncRequest(t *testing.T) {
|
||||||
defer fx.stop()
|
defer fx.stop()
|
||||||
|
|
||||||
peerId := "PeerId"
|
peerId := "PeerId"
|
||||||
|
peerCtx := peer.CtxWithPeerId(ctx, peerId)
|
||||||
peerMock := mock_peer.NewMockPeer(fx.ctrl)
|
peerMock := mock_peer.NewMockPeer(fx.ctrl)
|
||||||
conn := &drpcconn.Conn{}
|
conn := &drpcconn.Conn{}
|
||||||
msg := &spacesyncproto.ObjectSyncMessage{}
|
msg := &spacesyncproto.ObjectSyncMessage{}
|
||||||
resp := &spacesyncproto.ObjectSyncMessage{}
|
resp := &spacesyncproto.ObjectSyncMessage{}
|
||||||
fx.peerPoolMock.EXPECT().Get(ctx, peerId).Return(peerMock, nil)
|
fx.peerPoolMock.EXPECT().Get(ctx, peerId).Return(peerMock, nil)
|
||||||
fx.clientMock.EXPECT().ObjectSync(ctx, msg).Return(resp, nil)
|
fx.clientMock.EXPECT().ObjectSync(ctx, msg).Return(resp, nil)
|
||||||
|
peerMock.EXPECT().Context().Return(peerCtx).AnyTimes()
|
||||||
peerMock.EXPECT().DoDrpc(ctx, gomock.Any()).DoAndReturn(func(ctx context.Context, drpcHandler func(conn drpc.Conn) error) {
|
peerMock.EXPECT().DoDrpc(ctx, gomock.Any()).DoAndReturn(func(ctx context.Context, drpcHandler func(conn drpc.Conn) error) {
|
||||||
drpcHandler(conn)
|
drpcHandler(conn)
|
||||||
}).Return(nil)
|
}).Return(nil)
|
||||||
|
@ -86,12 +88,14 @@ func TestRequestManager_SyncRequest(t *testing.T) {
|
||||||
ctx = fx.requestManager.ctx
|
ctx = fx.requestManager.ctx
|
||||||
|
|
||||||
peerId := "PeerId"
|
peerId := "PeerId"
|
||||||
|
peerCtx := peer.CtxWithPeerId(ctx, peerId)
|
||||||
peerMock := mock_peer.NewMockPeer(fx.ctrl)
|
peerMock := mock_peer.NewMockPeer(fx.ctrl)
|
||||||
conn := &drpcconn.Conn{}
|
conn := &drpcconn.Conn{}
|
||||||
msg := &spacesyncproto.ObjectSyncMessage{}
|
msg := &spacesyncproto.ObjectSyncMessage{}
|
||||||
resp := &spacesyncproto.ObjectSyncMessage{}
|
resp := &spacesyncproto.ObjectSyncMessage{}
|
||||||
fx.peerPoolMock.EXPECT().Get(ctx, peerId).Return(peerMock, nil)
|
fx.peerPoolMock.EXPECT().Get(ctx, peerId).Return(peerMock, nil)
|
||||||
fx.clientMock.EXPECT().ObjectSync(ctx, msg).Return(resp, nil)
|
fx.clientMock.EXPECT().ObjectSync(ctx, msg).Return(resp, nil)
|
||||||
|
peerMock.EXPECT().Context().Return(peerCtx).AnyTimes()
|
||||||
peerMock.EXPECT().DoDrpc(ctx, gomock.Any()).DoAndReturn(func(ctx context.Context, drpcHandler func(conn drpc.Conn) error) {
|
peerMock.EXPECT().DoDrpc(ctx, gomock.Any()).DoAndReturn(func(ctx context.Context, drpcHandler func(conn drpc.Conn) error) {
|
||||||
drpcHandler(conn)
|
drpcHandler(conn)
|
||||||
}).Return(nil)
|
}).Return(nil)
|
||||||
|
|
|
@ -44,9 +44,8 @@ var (
|
||||||
DoSnapshot = objecttree.DoSnapshot
|
DoSnapshot = objecttree.DoSnapshot
|
||||||
buildHistoryTree = func(objTree objecttree.ObjectTree) (objecttree.ReadableObjectTree, error) {
|
buildHistoryTree = func(objTree objecttree.ObjectTree) (objecttree.ReadableObjectTree, error) {
|
||||||
return objecttree.BuildHistoryTree(objecttree.HistoryTreeParams{
|
return objecttree.BuildHistoryTree(objecttree.HistoryTreeParams{
|
||||||
TreeStorage: objTree.Storage(),
|
TreeStorage: objTree.Storage(),
|
||||||
AclList: objTree.AclList(),
|
AclList: objTree.AclList(),
|
||||||
BuildFullTree: true,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -298,7 +298,7 @@ func (m mockTreeSyncer) StartSync() {
|
||||||
func (m mockTreeSyncer) StopSync() {
|
func (m mockTreeSyncer) StopSync() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m mockTreeSyncer) SyncAll(ctx context.Context, peerId string, existing, missing []string) error {
|
func (m mockTreeSyncer) SyncAll(ctx context.Context, p peer.Peer, existing, missing []string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -364,6 +364,10 @@ var _ coordinatorclient.CoordinatorClient = (*mockCoordinatorClient)(nil)
|
||||||
type mockCoordinatorClient struct {
|
type mockCoordinatorClient struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m mockCoordinatorClient) IsNetworkNeedsUpdate(ctx context.Context) (bool, error) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m mockCoordinatorClient) SpaceMakeShareable(ctx context.Context, spaceId string) (err error) {
|
func (m mockCoordinatorClient) SpaceMakeShareable(ctx context.Context, spaceId string) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -424,6 +428,10 @@ func (m mockCoordinatorClient) AclGetRecords(ctx context.Context, spaceId, aclHe
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m mockCoordinatorClient) AclEventLog(ctx context.Context, accountId, lastRecordId string, limit int) (records []*coordinatorproto.AclEventLogRecord, err error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (m mockCoordinatorClient) Init(a *app.App) (err error) {
|
func (m mockCoordinatorClient) Init(a *app.App) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package syncstatus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/anyproto/any-sync/app"
|
"github.com/anyproto/any-sync/app"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -22,6 +23,12 @@ func (n *noOpSyncStatus) Name() (name string) {
|
||||||
func (n *noOpSyncStatus) HeadsChange(treeId string, heads []string) {
|
func (n *noOpSyncStatus) HeadsChange(treeId string, heads []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *noOpSyncStatus) ObjectReceive(senderId, treeId string, heads []string) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *noOpSyncStatus) HeadsApply(senderId, treeId string, heads []string, allAdded bool) {
|
||||||
|
}
|
||||||
|
|
||||||
func (n *noOpSyncStatus) HeadsReceive(senderId, treeId string, heads []string) {
|
func (n *noOpSyncStatus) HeadsReceive(senderId, treeId string, heads []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,4 +11,6 @@ type StatusUpdater interface {
|
||||||
|
|
||||||
HeadsChange(treeId string, heads []string)
|
HeadsChange(treeId string, heads []string)
|
||||||
HeadsReceive(senderId, treeId string, heads []string)
|
HeadsReceive(senderId, treeId string, heads []string)
|
||||||
|
ObjectReceive(senderId, treeId string, heads []string)
|
||||||
|
HeadsApply(senderId, treeId string, heads []string, allAdded bool)
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"github.com/anyproto/any-sync/net/peer"
|
"github.com/anyproto/any-sync/net/peer"
|
||||||
"github.com/anyproto/any-sync/net/pool"
|
"github.com/anyproto/any-sync/net/pool"
|
||||||
"github.com/anyproto/any-sync/net/rpc/rpcerr"
|
"github.com/anyproto/any-sync/net/rpc/rpcerr"
|
||||||
|
"github.com/anyproto/any-sync/net/secureservice"
|
||||||
"github.com/anyproto/any-sync/nodeconf"
|
"github.com/anyproto/any-sync/nodeconf"
|
||||||
"github.com/anyproto/any-sync/util/cidutil"
|
"github.com/anyproto/any-sync/util/cidutil"
|
||||||
"github.com/anyproto/any-sync/util/crypto"
|
"github.com/anyproto/any-sync/util/crypto"
|
||||||
|
@ -40,6 +41,7 @@ type CoordinatorClient interface {
|
||||||
SpaceMakeShareable(ctx context.Context, spaceId string) (err error)
|
SpaceMakeShareable(ctx context.Context, spaceId string) (err error)
|
||||||
SpaceMakeUnshareable(ctx context.Context, spaceId, aclId string) (err error)
|
SpaceMakeUnshareable(ctx context.Context, spaceId, aclId string) (err error)
|
||||||
NetworkConfiguration(ctx context.Context, currentId string) (*coordinatorproto.NetworkConfigurationResponse, error)
|
NetworkConfiguration(ctx context.Context, currentId string) (*coordinatorproto.NetworkConfigurationResponse, error)
|
||||||
|
IsNetworkNeedsUpdate(ctx context.Context) (bool, error)
|
||||||
DeletionLog(ctx context.Context, lastRecordId string, limit int) (records []*coordinatorproto.DeletionLogRecord, err error)
|
DeletionLog(ctx context.Context, lastRecordId string, limit int) (records []*coordinatorproto.DeletionLogRecord, err error)
|
||||||
|
|
||||||
IdentityRepoPut(ctx context.Context, identity string, data []*identityrepoproto.Data) (err error)
|
IdentityRepoPut(ctx context.Context, identity string, data []*identityrepoproto.Data) (err error)
|
||||||
|
@ -50,6 +52,8 @@ type CoordinatorClient interface {
|
||||||
|
|
||||||
AccountLimitsSet(ctx context.Context, req *coordinatorproto.AccountLimitsSetRequest) error
|
AccountLimitsSet(ctx context.Context, req *coordinatorproto.AccountLimitsSetRequest) error
|
||||||
|
|
||||||
|
AclEventLog(ctx context.Context, accountId, lastRecordId string, limit int) (records []*coordinatorproto.AclEventLogRecord, err error)
|
||||||
|
|
||||||
app.Component
|
app.Component
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,6 +336,34 @@ func (c *coordinatorClient) SpaceMakeUnshareable(ctx context.Context, spaceId, a
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *coordinatorClient) AclEventLog(ctx context.Context, accountId, lastRecordId string, limit int) (records []*coordinatorproto.AclEventLogRecord, err error) {
|
||||||
|
err = c.doClient(ctx, func(cl coordinatorproto.DRPCCoordinatorClient) error {
|
||||||
|
resp, err := cl.AclEventLog(ctx, &coordinatorproto.AclEventLogRequest{
|
||||||
|
AccountIdentity: accountId,
|
||||||
|
AfterId: lastRecordId,
|
||||||
|
Limit: uint32(limit),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return rpcerr.Unwrap(err)
|
||||||
|
}
|
||||||
|
records = resp.Records
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *coordinatorClient) IsNetworkNeedsUpdate(ctx context.Context) (bool, error) {
|
||||||
|
p, err := c.getPeer(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
version, err := peer.CtxProtoVersion(p.Context())
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return secureservice.ProtoVersion < version, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *coordinatorClient) doClient(ctx context.Context, f func(cl coordinatorproto.DRPCCoordinatorClient) error) error {
|
func (c *coordinatorClient) doClient(ctx context.Context, f func(cl coordinatorproto.DRPCCoordinatorClient) error) error {
|
||||||
p, err := c.getPeer(ctx)
|
p, err := c.getPeer(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
//
|
//
|
||||||
// mockgen -destination mock_coordinatorclient/mock_coordinatorclient.go github.com/anyproto/any-sync/coordinator/coordinatorclient CoordinatorClient
|
// mockgen -destination mock_coordinatorclient/mock_coordinatorclient.go github.com/anyproto/any-sync/coordinator/coordinatorclient CoordinatorClient
|
||||||
//
|
//
|
||||||
|
|
||||||
// Package mock_coordinatorclient is a generated GoMock package.
|
// Package mock_coordinatorclient is a generated GoMock package.
|
||||||
package mock_coordinatorclient
|
package mock_coordinatorclient
|
||||||
|
|
||||||
|
@ -102,6 +101,21 @@ func (mr *MockCoordinatorClientMockRecorder) AclAddRecord(arg0, arg1, arg2 any)
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AclAddRecord", reflect.TypeOf((*MockCoordinatorClient)(nil).AclAddRecord), arg0, arg1, arg2)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AclAddRecord", reflect.TypeOf((*MockCoordinatorClient)(nil).AclAddRecord), arg0, arg1, arg2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AclEventLog mocks base method.
|
||||||
|
func (m *MockCoordinatorClient) AclEventLog(arg0 context.Context, arg1, arg2 string, arg3 int) ([]*coordinatorproto.AclEventLogRecord, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "AclEventLog", arg0, arg1, arg2, arg3)
|
||||||
|
ret0, _ := ret[0].([]*coordinatorproto.AclEventLogRecord)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// AclEventLog indicates an expected call of AclEventLog.
|
||||||
|
func (mr *MockCoordinatorClientMockRecorder) AclEventLog(arg0, arg1, arg2, arg3 any) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AclEventLog", reflect.TypeOf((*MockCoordinatorClient)(nil).AclEventLog), arg0, arg1, arg2, arg3)
|
||||||
|
}
|
||||||
|
|
||||||
// AclGetRecords mocks base method.
|
// AclGetRecords mocks base method.
|
||||||
func (m *MockCoordinatorClient) AclGetRecords(arg0 context.Context, arg1, arg2 string) ([]*consensusproto.RawRecordWithId, error) {
|
func (m *MockCoordinatorClient) AclGetRecords(arg0 context.Context, arg1, arg2 string) ([]*consensusproto.RawRecordWithId, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
@ -175,6 +189,21 @@ func (mr *MockCoordinatorClientMockRecorder) Init(arg0 any) *gomock.Call {
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Init", reflect.TypeOf((*MockCoordinatorClient)(nil).Init), arg0)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Init", reflect.TypeOf((*MockCoordinatorClient)(nil).Init), arg0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsNetworkNeedsUpdate mocks base method.
|
||||||
|
func (m *MockCoordinatorClient) IsNetworkNeedsUpdate(arg0 context.Context) (bool, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "IsNetworkNeedsUpdate", arg0)
|
||||||
|
ret0, _ := ret[0].(bool)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNetworkNeedsUpdate indicates an expected call of IsNetworkNeedsUpdate.
|
||||||
|
func (mr *MockCoordinatorClientMockRecorder) IsNetworkNeedsUpdate(arg0 any) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsNetworkNeedsUpdate", reflect.TypeOf((*MockCoordinatorClient)(nil).IsNetworkNeedsUpdate), arg0)
|
||||||
|
}
|
||||||
|
|
||||||
// Name mocks base method.
|
// Name mocks base method.
|
||||||
func (m *MockCoordinatorClient) Name() string {
|
func (m *MockCoordinatorClient) Name() string {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -54,6 +54,7 @@ type DRPCCoordinatorClient interface {
|
||||||
AclAddRecord(ctx context.Context, in *AclAddRecordRequest) (*AclAddRecordResponse, error)
|
AclAddRecord(ctx context.Context, in *AclAddRecordRequest) (*AclAddRecordResponse, error)
|
||||||
AclGetRecords(ctx context.Context, in *AclGetRecordsRequest) (*AclGetRecordsResponse, error)
|
AclGetRecords(ctx context.Context, in *AclGetRecordsRequest) (*AclGetRecordsResponse, error)
|
||||||
AccountLimitsSet(ctx context.Context, in *AccountLimitsSetRequest) (*AccountLimitsSetResponse, error)
|
AccountLimitsSet(ctx context.Context, in *AccountLimitsSetRequest) (*AccountLimitsSetResponse, error)
|
||||||
|
AclEventLog(ctx context.Context, in *AclEventLogRequest) (*AclEventLogResponse, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type drpcCoordinatorClient struct {
|
type drpcCoordinatorClient struct {
|
||||||
|
@ -192,6 +193,15 @@ func (c *drpcCoordinatorClient) AccountLimitsSet(ctx context.Context, in *Accoun
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *drpcCoordinatorClient) AclEventLog(ctx context.Context, in *AclEventLogRequest) (*AclEventLogResponse, error) {
|
||||||
|
out := new(AclEventLogResponse)
|
||||||
|
err := c.cc.Invoke(ctx, "/coordinator.Coordinator/AclEventLog", drpcEncoding_File_coordinator_coordinatorproto_protos_coordinator_proto{}, in, out)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
type DRPCCoordinatorServer interface {
|
type DRPCCoordinatorServer interface {
|
||||||
SpaceSign(context.Context, *SpaceSignRequest) (*SpaceSignResponse, error)
|
SpaceSign(context.Context, *SpaceSignRequest) (*SpaceSignResponse, error)
|
||||||
SpaceStatusCheck(context.Context, *SpaceStatusCheckRequest) (*SpaceStatusCheckResponse, error)
|
SpaceStatusCheck(context.Context, *SpaceStatusCheckRequest) (*SpaceStatusCheckResponse, error)
|
||||||
|
@ -207,6 +217,7 @@ type DRPCCoordinatorServer interface {
|
||||||
AclAddRecord(context.Context, *AclAddRecordRequest) (*AclAddRecordResponse, error)
|
AclAddRecord(context.Context, *AclAddRecordRequest) (*AclAddRecordResponse, error)
|
||||||
AclGetRecords(context.Context, *AclGetRecordsRequest) (*AclGetRecordsResponse, error)
|
AclGetRecords(context.Context, *AclGetRecordsRequest) (*AclGetRecordsResponse, error)
|
||||||
AccountLimitsSet(context.Context, *AccountLimitsSetRequest) (*AccountLimitsSetResponse, error)
|
AccountLimitsSet(context.Context, *AccountLimitsSetRequest) (*AccountLimitsSetResponse, error)
|
||||||
|
AclEventLog(context.Context, *AclEventLogRequest) (*AclEventLogResponse, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type DRPCCoordinatorUnimplementedServer struct{}
|
type DRPCCoordinatorUnimplementedServer struct{}
|
||||||
|
@ -267,9 +278,13 @@ func (s *DRPCCoordinatorUnimplementedServer) AccountLimitsSet(context.Context, *
|
||||||
return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented)
|
return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *DRPCCoordinatorUnimplementedServer) AclEventLog(context.Context, *AclEventLogRequest) (*AclEventLogResponse, error) {
|
||||||
|
return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented)
|
||||||
|
}
|
||||||
|
|
||||||
type DRPCCoordinatorDescription struct{}
|
type DRPCCoordinatorDescription struct{}
|
||||||
|
|
||||||
func (DRPCCoordinatorDescription) NumMethods() int { return 14 }
|
func (DRPCCoordinatorDescription) NumMethods() int { return 15 }
|
||||||
|
|
||||||
func (DRPCCoordinatorDescription) Method(n int) (string, drpc.Encoding, drpc.Receiver, interface{}, bool) {
|
func (DRPCCoordinatorDescription) Method(n int) (string, drpc.Encoding, drpc.Receiver, interface{}, bool) {
|
||||||
switch n {
|
switch n {
|
||||||
|
@ -399,6 +414,15 @@ func (DRPCCoordinatorDescription) Method(n int) (string, drpc.Encoding, drpc.Rec
|
||||||
in1.(*AccountLimitsSetRequest),
|
in1.(*AccountLimitsSetRequest),
|
||||||
)
|
)
|
||||||
}, DRPCCoordinatorServer.AccountLimitsSet, true
|
}, DRPCCoordinatorServer.AccountLimitsSet, true
|
||||||
|
case 14:
|
||||||
|
return "/coordinator.Coordinator/AclEventLog", drpcEncoding_File_coordinator_coordinatorproto_protos_coordinator_proto{},
|
||||||
|
func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) {
|
||||||
|
return srv.(DRPCCoordinatorServer).
|
||||||
|
AclEventLog(
|
||||||
|
ctx,
|
||||||
|
in1.(*AclEventLogRequest),
|
||||||
|
)
|
||||||
|
}, DRPCCoordinatorServer.AclEventLog, true
|
||||||
default:
|
default:
|
||||||
return "", nil, nil, nil, false
|
return "", nil, nil, nil, false
|
||||||
}
|
}
|
||||||
|
@ -631,3 +655,19 @@ func (x *drpcCoordinator_AccountLimitsSetStream) SendAndClose(m *AccountLimitsSe
|
||||||
}
|
}
|
||||||
return x.CloseSend()
|
return x.CloseSend()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DRPCCoordinator_AclEventLogStream interface {
|
||||||
|
drpc.Stream
|
||||||
|
SendAndClose(*AclEventLogResponse) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type drpcCoordinator_AclEventLogStream struct {
|
||||||
|
drpc.Stream
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *drpcCoordinator_AclEventLogStream) SendAndClose(m *AclEventLogResponse) error {
|
||||||
|
if err := x.MsgSend(m, drpcEncoding_File_coordinator_coordinatorproto_protos_coordinator_proto{}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return x.CloseSend()
|
||||||
|
}
|
||||||
|
|
|
@ -43,6 +43,9 @@ service Coordinator {
|
||||||
rpc AclGetRecords(AclGetRecordsRequest) returns (AclGetRecordsResponse);
|
rpc AclGetRecords(AclGetRecordsRequest) returns (AclGetRecordsResponse);
|
||||||
// AccountLimitsSet sets limits to the account. Can be used only by a network config member
|
// AccountLimitsSet sets limits to the account. Can be used only by a network config member
|
||||||
rpc AccountLimitsSet(AccountLimitsSetRequest) returns (AccountLimitsSetResponse);
|
rpc AccountLimitsSet(AccountLimitsSetRequest) returns (AccountLimitsSetResponse);
|
||||||
|
|
||||||
|
// EventLog gets the latest event log records
|
||||||
|
rpc AclEventLog(AclEventLogRequest) returns (AclEventLogResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
message SpaceSignRequest {
|
message SpaceSignRequest {
|
||||||
|
@ -364,5 +367,39 @@ message AccountLimitsSetRequest {
|
||||||
uint32 sharedSpacesLimit = 6;
|
uint32 sharedSpacesLimit = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
message AccountLimitsSetResponse {}
|
message AccountLimitsSetResponse {}
|
||||||
|
|
||||||
|
message AclEventLogRequest {
|
||||||
|
string accountIdentity = 1;
|
||||||
|
// AfterId is the last known logId to request records after this id. If it is empty will be returned a list from the beginning.
|
||||||
|
string afterId = 2;
|
||||||
|
// Limit is a desired record count in response
|
||||||
|
uint32 limit = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message AclEventLogResponse {
|
||||||
|
// AclEventLogRecord list of records, if there are no new records will be empty
|
||||||
|
repeated AclEventLogRecord records = 1;
|
||||||
|
// HasMore indicates if there are records left
|
||||||
|
bool hasMore = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum AclEventLogRecordType {
|
||||||
|
RecordTypeSpaceReceipt = 0;
|
||||||
|
RecordTypeSpaceShared = 1;
|
||||||
|
RecordTypeSpaceUnshared = 2;
|
||||||
|
RecordTypeSpaceAclAddRecord = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message AclEventLogRecord {
|
||||||
|
// Id is a record id
|
||||||
|
string id = 1;
|
||||||
|
// SpaceId is a space identifier
|
||||||
|
string spaceId = 2;
|
||||||
|
// Timestamp is a unixtimestamp of record creation
|
||||||
|
int64 timestamp = 3;
|
||||||
|
// Type of current event
|
||||||
|
AclEventLogRecordType type = 4;
|
||||||
|
// only for RecordTypeSpaceAclAddRecord
|
||||||
|
string aclChangeId = 5;
|
||||||
|
}
|
|
@ -66,6 +66,7 @@ func (n *nodeConfSource) GetLast(ctx context.Context, currentId string) (c nodec
|
||||||
Types: types,
|
Types: types,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nodeconf.Configuration{
|
return nodeconf.Configuration{
|
||||||
Id: res.ConfigurationId,
|
Id: res.ConfigurationId,
|
||||||
NetworkId: res.NetworkId,
|
NetworkId: res.NetworkId,
|
||||||
|
|
22
go.mod
22
go.mod
|
@ -12,7 +12,7 @@ require (
|
||||||
github.com/cespare/xxhash v1.1.0
|
github.com/cespare/xxhash v1.1.0
|
||||||
github.com/cheggaaa/mb/v3 v3.0.2
|
github.com/cheggaaa/mb/v3 v3.0.2
|
||||||
github.com/gobwas/glob v0.2.3
|
github.com/gobwas/glob v0.2.3
|
||||||
github.com/goccy/go-graphviz v0.1.2
|
github.com/goccy/go-graphviz v0.1.3
|
||||||
github.com/gogo/protobuf v1.3.2
|
github.com/gogo/protobuf v1.3.2
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/hashicorp/yamux v0.1.1
|
github.com/hashicorp/yamux v0.1.1
|
||||||
|
@ -21,21 +21,21 @@ require (
|
||||||
github.com/ipfs/go-block-format v0.2.0
|
github.com/ipfs/go-block-format v0.2.0
|
||||||
github.com/ipfs/go-cid v0.4.1
|
github.com/ipfs/go-cid v0.4.1
|
||||||
github.com/ipfs/go-ipld-format v0.6.0
|
github.com/ipfs/go-ipld-format v0.6.0
|
||||||
github.com/libp2p/go-libp2p v0.33.2
|
github.com/libp2p/go-libp2p v0.35.1
|
||||||
github.com/mr-tron/base58 v1.2.0
|
github.com/mr-tron/base58 v1.2.0
|
||||||
github.com/multiformats/go-multibase v0.2.0
|
github.com/multiformats/go-multibase v0.2.0
|
||||||
github.com/multiformats/go-multihash v0.2.3
|
github.com/multiformats/go-multihash v0.2.3
|
||||||
github.com/prometheus/client_golang v1.19.1
|
github.com/prometheus/client_golang v1.19.1
|
||||||
github.com/quic-go/quic-go v0.44.0
|
github.com/quic-go/quic-go v0.46.0
|
||||||
github.com/stretchr/testify v1.9.0
|
github.com/stretchr/testify v1.9.0
|
||||||
github.com/tyler-smith/go-bip39 v1.1.0
|
github.com/tyler-smith/go-bip39 v1.1.0
|
||||||
github.com/zeebo/blake3 v0.2.3
|
github.com/zeebo/blake3 v0.2.3
|
||||||
go.uber.org/atomic v1.11.0
|
go.uber.org/atomic v1.11.0
|
||||||
go.uber.org/mock v0.4.0
|
go.uber.org/mock v0.4.0
|
||||||
go.uber.org/zap v1.27.0
|
go.uber.org/zap v1.27.0
|
||||||
golang.org/x/crypto v0.23.0
|
golang.org/x/crypto v0.26.0
|
||||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
|
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
|
||||||
golang.org/x/net v0.25.0
|
golang.org/x/net v0.28.0
|
||||||
golang.org/x/time v0.5.0
|
golang.org/x/time v0.5.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
storj.io/drpc v0.0.34
|
storj.io/drpc v0.0.34
|
||||||
|
@ -49,7 +49,7 @@ require (
|
||||||
github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect
|
github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
|
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
|
||||||
github.com/fogleman/gg v1.3.0 // indirect
|
github.com/fogleman/gg v1.3.0 // indirect
|
||||||
github.com/go-logr/logr v1.4.1 // indirect
|
github.com/go-logr/logr v1.4.1 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
|
@ -57,7 +57,7 @@ require (
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||||
github.com/golang/protobuf v1.5.4 // indirect
|
github.com/golang/protobuf v1.5.4 // indirect
|
||||||
github.com/google/pprof v0.0.0-20240402174815-29b9bb013b0f // indirect
|
github.com/google/pprof v0.0.0-20240402174815-29b9bb013b0f // indirect
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.5 // indirect
|
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||||
github.com/ipfs/bbloom v0.0.4 // indirect
|
github.com/ipfs/bbloom v0.0.4 // indirect
|
||||||
github.com/ipfs/go-bitfield v1.1.0 // indirect
|
github.com/ipfs/go-bitfield v1.1.0 // indirect
|
||||||
github.com/ipfs/go-datastore v0.6.0 // indirect
|
github.com/ipfs/go-datastore v0.6.0 // indirect
|
||||||
|
@ -75,7 +75,7 @@ require (
|
||||||
github.com/minio/sha256-simd v1.0.1 // indirect
|
github.com/minio/sha256-simd v1.0.1 // indirect
|
||||||
github.com/multiformats/go-base32 v0.1.0 // indirect
|
github.com/multiformats/go-base32 v0.1.0 // indirect
|
||||||
github.com/multiformats/go-base36 v0.2.0 // indirect
|
github.com/multiformats/go-base36 v0.2.0 // indirect
|
||||||
github.com/multiformats/go-multiaddr v0.12.3 // indirect
|
github.com/multiformats/go-multiaddr v0.12.4 // indirect
|
||||||
github.com/multiformats/go-multicodec v0.9.0 // indirect
|
github.com/multiformats/go-multicodec v0.9.0 // indirect
|
||||||
github.com/multiformats/go-multistream v0.5.0 // indirect
|
github.com/multiformats/go-multistream v0.5.0 // indirect
|
||||||
github.com/multiformats/go-varint v0.0.7 // indirect
|
github.com/multiformats/go-varint v0.0.7 // indirect
|
||||||
|
@ -83,7 +83,7 @@ require (
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/polydawn/refmt v0.89.0 // indirect
|
github.com/polydawn/refmt v0.89.0 // indirect
|
||||||
github.com/prometheus/client_model v0.6.0 // indirect
|
github.com/prometheus/client_model v0.6.1 // indirect
|
||||||
github.com/prometheus/common v0.48.0 // indirect
|
github.com/prometheus/common v0.48.0 // indirect
|
||||||
github.com/prometheus/procfs v0.12.0 // indirect
|
github.com/prometheus/procfs v0.12.0 // indirect
|
||||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||||
|
@ -95,8 +95,8 @@ require (
|
||||||
golang.org/x/image v0.14.0 // indirect
|
golang.org/x/image v0.14.0 // indirect
|
||||||
golang.org/x/mod v0.17.0 // indirect
|
golang.org/x/mod v0.17.0 // indirect
|
||||||
golang.org/x/sync v0.7.0 // indirect
|
golang.org/x/sync v0.7.0 // indirect
|
||||||
golang.org/x/sys v0.20.0 // indirect
|
golang.org/x/sys v0.23.0 // indirect
|
||||||
golang.org/x/tools v0.21.0 // indirect
|
golang.org/x/tools v0.21.0 // indirect
|
||||||
google.golang.org/protobuf v1.33.0 // indirect
|
google.golang.org/protobuf v1.34.1 // indirect
|
||||||
lukechampine.com/blake3 v1.2.1 // indirect
|
lukechampine.com/blake3 v1.2.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
88
go.sum
88
go.sum
|
@ -52,8 +52,8 @@ github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR
|
||||||
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U=
|
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U=
|
||||||
github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
|
github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
|
||||||
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
|
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg=
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
|
||||||
github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg=
|
github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg=
|
||||||
github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=
|
github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=
|
||||||
github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
|
github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
|
||||||
|
@ -73,8 +73,8 @@ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4
|
||||||
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
|
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
|
||||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||||
github.com/goccy/go-graphviz v0.1.2 h1:sWSJ6w13BCm/ZOUTHDVrdvbsxqN8yyzaFcHrH/hQ9Yg=
|
github.com/goccy/go-graphviz v0.1.3 h1:Pkt8y4FBnBNI9tfSobpoN5qy1qMNqRXPQYvLhaSUasY=
|
||||||
github.com/goccy/go-graphviz v0.1.2/go.mod h1:pMYpbAqJT10V8dzV1JN/g/wUlG/0imKPzn3ZsrchGCI=
|
github.com/goccy/go-graphviz v0.1.3/go.mod h1:pMYpbAqJT10V8dzV1JN/g/wUlG/0imKPzn3ZsrchGCI=
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||||
|
@ -93,8 +93,8 @@ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4=
|
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4=
|
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||||
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
|
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
|
||||||
github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
|
github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
|
@ -154,8 +154,8 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||||
github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI=
|
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
||||||
github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
|
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||||
|
@ -170,8 +170,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8=
|
github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8=
|
||||||
github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg=
|
github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg=
|
||||||
github.com/libp2p/go-libp2p v0.33.2 h1:vCdwnFxoGOXMKmaGHlDSnL4bM3fQeW8pgIa9DECnb40=
|
github.com/libp2p/go-libp2p v0.35.1 h1:Hm7Ub2BF+GCb14ojcsEK6WAy5it5smPDK02iXSZLl50=
|
||||||
github.com/libp2p/go-libp2p v0.33.2/go.mod h1:zTeppLuCvUIkT118pFVzA8xzP/p2dJYOMApCkFh0Yww=
|
github.com/libp2p/go-libp2p v0.35.1/go.mod h1:Dnkgba5hsfSv5dvvXC8nfqk44hH0gIKKno+HOMU0fdc=
|
||||||
github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94=
|
github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94=
|
||||||
github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8=
|
github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8=
|
||||||
github.com/libp2p/go-libp2p-record v0.2.0 h1:oiNUOCWno2BFuxt3my4i1frNrt7PerzB3queqa1NkQ0=
|
github.com/libp2p/go-libp2p-record v0.2.0 h1:oiNUOCWno2BFuxt3my4i1frNrt7PerzB3queqa1NkQ0=
|
||||||
|
@ -202,8 +202,8 @@ github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aG
|
||||||
github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI=
|
github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI=
|
||||||
github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0=
|
github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0=
|
||||||
github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4=
|
github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4=
|
||||||
github.com/multiformats/go-multiaddr v0.12.3 h1:hVBXvPRcKG0w80VinQ23P5t7czWgg65BmIvQKjDydU8=
|
github.com/multiformats/go-multiaddr v0.12.4 h1:rrKqpY9h+n80EwhhC/kkcunCZZ7URIF8yN1WEUt2Hvc=
|
||||||
github.com/multiformats/go-multiaddr v0.12.3/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII=
|
github.com/multiformats/go-multiaddr v0.12.4/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII=
|
||||||
github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A=
|
github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A=
|
||||||
github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk=
|
github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk=
|
||||||
github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E=
|
github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E=
|
||||||
|
@ -229,6 +229,38 @@ github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3Hig
|
||||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
|
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
|
||||||
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
|
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
|
||||||
|
github.com/pion/datachannel v1.5.6 h1:1IxKJntfSlYkpUj8LlYRSWpYiTTC02nUrOE8T3DqGeg=
|
||||||
|
github.com/pion/datachannel v1.5.6/go.mod h1:1eKT6Q85pRnr2mHiWHxJwO50SfZRtWHTsNIVb/NfGW4=
|
||||||
|
github.com/pion/dtls/v2 v2.2.11 h1:9U/dpCYl1ySttROPWJgqWKEylUdT0fXp/xst6JwY5Ks=
|
||||||
|
github.com/pion/dtls/v2 v2.2.11/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE=
|
||||||
|
github.com/pion/ice/v2 v2.3.25 h1:M5rJA07dqhi3nobJIg+uPtcVjFECTrhcR3n0ns8kDZs=
|
||||||
|
github.com/pion/ice/v2 v2.3.25/go.mod h1:KXJJcZK7E8WzrBEYnV4UtqEZsGeWfHxsNqhVcVvgjxw=
|
||||||
|
github.com/pion/interceptor v0.1.29 h1:39fsnlP1U8gw2JzOFWdfCU82vHvhW9o0rZnZF56wF+M=
|
||||||
|
github.com/pion/interceptor v0.1.29/go.mod h1:ri+LGNjRUc5xUNtDEPzfdkmSqISixVTBF/z/Zms/6T4=
|
||||||
|
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
|
||||||
|
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
|
||||||
|
github.com/pion/mdns v0.0.12 h1:CiMYlY+O0azojWDmxdNr7ADGrnZ+V6Ilfner+6mSVK8=
|
||||||
|
github.com/pion/mdns v0.0.12/go.mod h1:VExJjv8to/6Wqm1FXK+Ii/Z9tsVk/F5sD/N70cnYFbk=
|
||||||
|
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
|
||||||
|
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
|
||||||
|
github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE=
|
||||||
|
github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4=
|
||||||
|
github.com/pion/rtp v1.8.6 h1:MTmn/b0aWWsAzux2AmP8WGllusBVw4NPYPVFFd7jUPw=
|
||||||
|
github.com/pion/rtp v1.8.6/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU=
|
||||||
|
github.com/pion/sctp v1.8.16 h1:PKrMs+o9EMLRvFfXq59WFsC+V8mN1wnKzqrv+3D/gYY=
|
||||||
|
github.com/pion/sctp v1.8.16/go.mod h1:P6PbDVA++OJMrVNg2AL3XtYHV4uD6dvfyOovCgMs0PE=
|
||||||
|
github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY=
|
||||||
|
github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M=
|
||||||
|
github.com/pion/srtp/v2 v2.0.18 h1:vKpAXfawO9RtTRKZJbG4y0v1b11NZxQnxRl85kGuUlo=
|
||||||
|
github.com/pion/srtp/v2 v2.0.18/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA=
|
||||||
|
github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4=
|
||||||
|
github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8=
|
||||||
|
github.com/pion/transport/v2 v2.2.5 h1:iyi25i/21gQck4hfRhomF6SktmUQjRsRW4WJdhfc3Kc=
|
||||||
|
github.com/pion/transport/v2 v2.2.5/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0=
|
||||||
|
github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc=
|
||||||
|
github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY=
|
||||||
|
github.com/pion/webrtc/v3 v3.2.40 h1:Wtfi6AZMQg+624cvCXUuSmrKWepSB7zfgYDOYqsSOVU=
|
||||||
|
github.com/pion/webrtc/v3 v3.2.40/go.mod h1:M1RAe3TNTD1tzyvqHrbVODfwdPGSXOUo/OgpoGGJqFY=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
@ -238,18 +270,18 @@ github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4
|
||||||
github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw=
|
github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw=
|
||||||
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
|
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
|
||||||
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
|
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
|
||||||
github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos=
|
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||||
github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8=
|
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||||
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
|
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
|
||||||
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
|
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
|
||||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||||
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
|
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
|
||||||
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
||||||
github.com/quic-go/quic-go v0.44.0 h1:So5wOr7jyO4vzL2sd8/pD9Kesciv91zSk8BoFngItQ0=
|
github.com/quic-go/quic-go v0.46.0 h1:uuwLClEEyk1DNvchH8uCByQVjo3yKL9opKulExNDs7Y=
|
||||||
github.com/quic-go/quic-go v0.44.0/go.mod h1:z4cx/9Ny9UtGITIPzmPTXh1ULfOyWh4qGQlpnPcWmek=
|
github.com/quic-go/quic-go v0.46.0/go.mod h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI=
|
||||||
github.com/quic-go/webtransport-go v0.6.0 h1:CvNsKqc4W2HljHJnoT+rMmbRJybShZ0YPFDD3NxaZLY=
|
github.com/quic-go/webtransport-go v0.8.0 h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv/cD7QFJg=
|
||||||
github.com/quic-go/webtransport-go v0.6.0/go.mod h1:9KjU4AEBqEQidGHNDkZrb8CAa1abRaosM2yGOyiikEc=
|
github.com/quic-go/webtransport-go v0.8.0/go.mod h1:N99tjprW432Ut5ONql/aUhSLT0YVSlwHohQsuac9WaM=
|
||||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
@ -314,8 +346,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||||
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
|
||||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
||||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
|
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
|
||||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
|
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
|
||||||
golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4=
|
golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4=
|
||||||
|
@ -333,8 +365,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
||||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
@ -353,13 +385,13 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
|
||||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
||||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
@ -375,8 +407,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
|
|
@ -71,7 +71,7 @@ func New() AnyNsClientService {
|
||||||
func (s *service) doClient(ctx context.Context, fn func(cl nsp.DRPCAnynsClient) error) error {
|
func (s *service) doClient(ctx context.Context, fn func(cl nsp.DRPCAnynsClient) error) error {
|
||||||
if len(s.nodeconf.NamingNodePeers()) == 0 {
|
if len(s.nodeconf.NamingNodePeers()) == 0 {
|
||||||
log.Error("no namingNode peers configured")
|
log.Error("no namingNode peers configured")
|
||||||
return errors.New("no namingNode peers configured")
|
return errors.New("no namingNode peers configured. Node config ID: " + s.nodeconf.Id())
|
||||||
}
|
}
|
||||||
|
|
||||||
// it will try to connect to the Naming Node
|
// it will try to connect to the Naming Node
|
||||||
|
|
|
@ -17,11 +17,13 @@ const (
|
||||||
contextKeyIdentity
|
contextKeyIdentity
|
||||||
contextKeyPeerAddr
|
contextKeyPeerAddr
|
||||||
contextKeyPeerClientVersion
|
contextKeyPeerClientVersion
|
||||||
|
contextKeyPeerProtoVersion
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrPeerIdNotFoundInContext = errors.New("peer id not found in context")
|
ErrPeerIdNotFoundInContext = errors.New("peer id not found in context")
|
||||||
ErrIdentityNotFoundInContext = errors.New("identity not found in context")
|
ErrProtoVersionNotFoundInContext = errors.New("proto version not found in context")
|
||||||
|
ErrIdentityNotFoundInContext = errors.New("identity not found in context")
|
||||||
)
|
)
|
||||||
|
|
||||||
const CtxResponsiblePeers = "*"
|
const CtxResponsiblePeers = "*"
|
||||||
|
@ -42,6 +44,19 @@ func CtxWithPeerId(ctx context.Context, peerId string) context.Context {
|
||||||
return context.WithValue(ctx, contextKeyPeerId, peerId)
|
return context.WithValue(ctx, contextKeyPeerId, peerId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CtxWithProtoVersion sets peer protocol version
|
||||||
|
func CtxWithProtoVersion(ctx context.Context, version uint32) context.Context {
|
||||||
|
return context.WithValue(ctx, contextKeyPeerProtoVersion, version)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CtxProtoVersion returns peer protocol version
|
||||||
|
func CtxProtoVersion(ctx context.Context) (uint32, error) {
|
||||||
|
if protoVersion, ok := ctx.Value(contextKeyPeerProtoVersion).(uint32); ok {
|
||||||
|
return protoVersion, nil
|
||||||
|
}
|
||||||
|
return 0, ErrProtoVersionNotFoundInContext
|
||||||
|
}
|
||||||
|
|
||||||
// CtxPeerAddr returns peer address
|
// CtxPeerAddr returns peer address
|
||||||
func CtxPeerAddr(ctx context.Context) string {
|
func CtxPeerAddr(ctx context.Context) string {
|
||||||
if p, ok := ctx.Value(contextKeyPeerAddr).(string); ok {
|
if p, ok := ctx.Value(contextKeyPeerAddr).(string); ok {
|
||||||
|
|
14
net/peer/context_test.go
Normal file
14
net/peer/context_test.go
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
package peer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCtxProtoVersion(t *testing.T) {
|
||||||
|
ctx := CtxWithProtoVersion(ctx, 1)
|
||||||
|
ver, err := CtxProtoVersion(ctx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, uint32(1), ver)
|
||||||
|
}
|
|
@ -2,6 +2,10 @@ package rpctest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"storj.io/drpc"
|
||||||
|
|
||||||
"github.com/anyproto/any-sync/net/peer"
|
"github.com/anyproto/any-sync/net/peer"
|
||||||
"github.com/anyproto/any-sync/net/rpc/rpctest/multiconntest"
|
"github.com/anyproto/any-sync/net/rpc/rpctest/multiconntest"
|
||||||
"github.com/anyproto/any-sync/net/transport"
|
"github.com/anyproto/any-sync/net/transport"
|
||||||
|
@ -10,3 +14,50 @@ import (
|
||||||
func MultiConnPair(peerIdServ, peerIdClient string) (serv, client transport.MultiConn) {
|
func MultiConnPair(peerIdServ, peerIdClient string) (serv, client transport.MultiConn) {
|
||||||
return multiconntest.MultiConnPair(peer.CtxWithPeerId(context.Background(), peerIdServ), peer.CtxWithPeerId(context.Background(), peerIdClient))
|
return multiconntest.MultiConnPair(peer.CtxWithPeerId(context.Background(), peerIdServ), peer.CtxWithPeerId(context.Background(), peerIdClient))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MockPeer struct {
|
||||||
|
Ctx context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MockPeer) CloseChan() <-chan struct{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MockPeer) SetTTL(ttl time.Duration) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MockPeer) Id() string {
|
||||||
|
return "peerId"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MockPeer) Context() context.Context {
|
||||||
|
if m.Ctx != nil {
|
||||||
|
return m.Ctx
|
||||||
|
}
|
||||||
|
return context.Background()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MockPeer) AcquireDrpcConn(ctx context.Context) (drpc.Conn, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MockPeer) ReleaseDrpcConn(conn drpc.Conn) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MockPeer) DoDrpc(ctx context.Context, do func(conn drpc.Conn) error) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MockPeer) IsClosed() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MockPeer) TryClose(objectTTL time.Duration) (res bool, err error) {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MockPeer) Close() (err error) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -28,11 +28,13 @@ var (
|
||||||
// ProtoVersion 1 - version with yamux over tcp and quic
|
// ProtoVersion 1 - version with yamux over tcp and quic
|
||||||
// ProtoVersion 2 - acl compatible version
|
// ProtoVersion 2 - acl compatible version
|
||||||
// ProtoVersion 3 - acl with breaking changes / multiplayer
|
// ProtoVersion 3 - acl with breaking changes / multiplayer
|
||||||
ProtoVersion = uint32(3)
|
AclCompatibleVersion = uint32(2)
|
||||||
|
ProtoVersion = uint32(3)
|
||||||
|
NewSyncProtoVersion = uint32(4)
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
compatibleVersions = []uint32{2, ProtoVersion}
|
compatibleVersions = []uint32{AclCompatibleVersion, ProtoVersion, NewSyncProtoVersion}
|
||||||
)
|
)
|
||||||
|
|
||||||
func New() SecureService {
|
func New() SecureService {
|
||||||
|
@ -119,6 +121,7 @@ func (s *secureService) HandshakeInbound(ctx context.Context, conn io.ReadWriteC
|
||||||
cctx = peer.CtxWithPeerId(cctx, peerId)
|
cctx = peer.CtxWithPeerId(cctx, peerId)
|
||||||
cctx = peer.CtxWithIdentity(cctx, res.Identity)
|
cctx = peer.CtxWithIdentity(cctx, res.Identity)
|
||||||
cctx = peer.CtxWithClientVersion(cctx, res.ClientVersion)
|
cctx = peer.CtxWithClientVersion(cctx, res.ClientVersion)
|
||||||
|
cctx = peer.CtxWithProtoVersion(cctx, res.ProtoVersion)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,6 +149,7 @@ func (s *secureService) HandshakeOutbound(ctx context.Context, conn io.ReadWrite
|
||||||
cctx = peer.CtxWithPeerId(cctx, peerId)
|
cctx = peer.CtxWithPeerId(cctx, peerId)
|
||||||
cctx = peer.CtxWithIdentity(cctx, res.Identity)
|
cctx = peer.CtxWithIdentity(cctx, res.Identity)
|
||||||
cctx = peer.CtxWithClientVersion(cctx, res.ClientVersion)
|
cctx = peer.CtxWithClientVersion(cctx, res.ClientVersion)
|
||||||
|
cctx = peer.CtxWithProtoVersion(cctx, res.ProtoVersion)
|
||||||
return cctx, nil
|
return cctx, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"github.com/anyproto/any-sync/app/debugstat"
|
"github.com/anyproto/any-sync/app/debugstat"
|
||||||
"github.com/anyproto/any-sync/net"
|
"github.com/anyproto/any-sync/net"
|
||||||
"github.com/anyproto/any-sync/net/peer"
|
"github.com/anyproto/any-sync/net/peer"
|
||||||
|
"github.com/anyproto/any-sync/net/secureservice"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StreamHandler handles incoming messages from streams
|
// StreamHandler handles incoming messages from streams
|
||||||
|
@ -293,6 +294,11 @@ func (s *streamPool) openStream(ctx context.Context, p peer.Peer) *openingProces
|
||||||
// in case there was no peerId in context
|
// in case there was no peerId in context
|
||||||
ctx := peer.CtxWithPeerId(ctx, p.Id())
|
ctx := peer.CtxWithPeerId(ctx, p.Id())
|
||||||
// open new stream and add to pool
|
// open new stream and add to pool
|
||||||
|
peerProto, err := peer.CtxProtoVersion(p.Context())
|
||||||
|
if err != nil {
|
||||||
|
peerProto = secureservice.ProtoVersion
|
||||||
|
}
|
||||||
|
ctx = peer.CtxWithProtoVersion(ctx, peerProto)
|
||||||
st, tags, err := s.handler.OpenStream(ctx, p)
|
st, tags, err := s.handler.OpenStream(ctx, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
op.err = err
|
op.err = err
|
||||||
|
|
|
@ -3,6 +3,10 @@ package yamux
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/anyproto/any-sync/app"
|
"github.com/anyproto/any-sync/app"
|
||||||
"github.com/anyproto/any-sync/app/logger"
|
"github.com/anyproto/any-sync/app/logger"
|
||||||
"github.com/anyproto/any-sync/net/connutil"
|
"github.com/anyproto/any-sync/net/connutil"
|
||||||
|
@ -10,9 +14,6 @@ import (
|
||||||
"github.com/anyproto/any-sync/net/transport"
|
"github.com/anyproto/any-sync/net/transport"
|
||||||
"github.com/hashicorp/yamux"
|
"github.com/hashicorp/yamux"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"net"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const CName = "net.transport.yamux"
|
const CName = "net.transport.yamux"
|
||||||
|
@ -157,18 +158,18 @@ func (y *yamuxTransport) accept(conn net.Conn) {
|
||||||
defer cancel()
|
defer cancel()
|
||||||
cctx, err := y.secure.SecureInbound(ctx, conn)
|
cctx, err := y.secure.SecureInbound(ctx, conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("incoming connection handshake error", zap.Error(err))
|
log.Info("incoming connection handshake error", zap.Error(err), zap.String("remoteAddr", conn.RemoteAddr().String()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
luc := connutil.NewLastUsageConn(connutil.NewTimeout(conn, time.Duration(y.conf.WriteTimeoutSec)*time.Second))
|
luc := connutil.NewLastUsageConn(connutil.NewTimeout(conn, time.Duration(y.conf.WriteTimeoutSec)*time.Second))
|
||||||
sess, err := yamux.Server(luc, y.yamuxConf)
|
sess, err := yamux.Server(luc, y.yamuxConf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("incoming connection yamux session error", zap.Error(err))
|
log.Info("incoming connection yamux session error", zap.Error(err), zap.String("remoteAddr", conn.RemoteAddr().String()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
mc := NewMultiConn(cctx, luc, conn.RemoteAddr().String(), sess)
|
mc := NewMultiConn(cctx, luc, conn.RemoteAddr().String(), sess)
|
||||||
if err = y.accepter.Accept(mc); err != nil {
|
if err = y.accepter.Accept(mc); err != nil {
|
||||||
log.Warn("connection accept error", zap.Error(err))
|
log.Info("connection accept error", zap.Error(err), zap.String("remoteAddr", conn.RemoteAddr().String()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,5 +61,5 @@ func (n *nodeConfStore) SaveLast(ctx context.Context, c nodeconf.Configuration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return os.WriteFile(path, data, 0755)
|
return os.WriteFile(path, data, 0644)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package nodeconf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
commonaccount "github.com/anyproto/any-sync/accountservice"
|
commonaccount "github.com/anyproto/any-sync/accountservice"
|
||||||
|
@ -31,6 +32,7 @@ const (
|
||||||
NetworkCompatibilityStatusOk
|
NetworkCompatibilityStatusOk
|
||||||
NetworkCompatibilityStatusError
|
NetworkCompatibilityStatusError
|
||||||
NetworkCompatibilityStatusIncompatible
|
NetworkCompatibilityStatusIncompatible
|
||||||
|
NetworkCompatibilityStatusNeedsUpdate
|
||||||
)
|
)
|
||||||
|
|
||||||
func New() Service {
|
func New() Service {
|
||||||
|
@ -43,6 +45,10 @@ type Service interface {
|
||||||
app.ComponentRunnable
|
app.ComponentRunnable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NetworkProtoVersionChecker interface {
|
||||||
|
IsNetworkNeedsUpdate(ctx context.Context) (bool, error)
|
||||||
|
}
|
||||||
|
|
||||||
type service struct {
|
type service struct {
|
||||||
accountId string
|
accountId string
|
||||||
config Configuration
|
config Configuration
|
||||||
|
@ -52,7 +58,8 @@ type service struct {
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
sync periodicsync.PeriodicSync
|
sync periodicsync.PeriodicSync
|
||||||
|
|
||||||
compatibilityStatus NetworkCompatibilityStatus
|
compatibilityStatus NetworkCompatibilityStatus
|
||||||
|
networkProtoVersionChecker NetworkProtoVersionChecker
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) Init(a *app.App) (err error) {
|
func (s *service) Init(a *app.App) (err error) {
|
||||||
|
@ -79,6 +86,7 @@ func (s *service) Init(a *app.App) (err error) {
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}, log)
|
}, log)
|
||||||
|
s.networkProtoVersionChecker = app.MustComponent[NetworkProtoVersionChecker](a)
|
||||||
return s.setLastConfiguration(lastStored)
|
return s.setLastConfiguration(lastStored)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,16 +107,68 @@ func (s *service) NetworkCompatibilityStatus() NetworkCompatibilityStatus {
|
||||||
|
|
||||||
func (s *service) updateConfiguration(ctx context.Context) (err error) {
|
func (s *service) updateConfiguration(ctx context.Context) (err error) {
|
||||||
last, err := s.source.GetLast(ctx, s.Configuration().Id)
|
last, err := s.source.GetLast(ctx, s.Configuration().Id)
|
||||||
if err != nil {
|
if err != nil && !errors.Is(err, ErrConfigurationNotChanged) {
|
||||||
s.setCompatibilityStatusByErr(err)
|
s.setCompatibilityStatusByErr(err)
|
||||||
return
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = s.updateCompatibilityStatus(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = s.saveAndSetLastConfiguration(ctx, last); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) updateCompatibilityStatus(ctx context.Context) error {
|
||||||
|
needsUpdate, checkErr := s.networkProtoVersionChecker.IsNetworkNeedsUpdate(ctx)
|
||||||
|
if checkErr != nil {
|
||||||
|
return checkErr
|
||||||
|
}
|
||||||
|
if needsUpdate {
|
||||||
|
s.setCompatibilityStatus(NetworkCompatibilityStatusNeedsUpdate)
|
||||||
} else {
|
} else {
|
||||||
s.setCompatibilityStatusByErr(nil)
|
s.setCompatibilityStatus(NetworkCompatibilityStatusOk)
|
||||||
}
|
}
|
||||||
if err = s.store.SaveLast(ctx, last); err != nil {
|
return nil
|
||||||
return
|
}
|
||||||
|
|
||||||
|
func (s *service) saveAndSetLastConfiguration(ctx context.Context, last Configuration) error {
|
||||||
|
if err := s.store.SaveLast(ctx, last); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
return s.setLastConfiguration(last)
|
|
||||||
|
if err := s.setLastConfiguration(last); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) setCompatibilityStatus(status NetworkCompatibilityStatus) {
|
||||||
|
s.mu.Lock()
|
||||||
|
defer s.mu.Unlock()
|
||||||
|
s.compatibilityStatus = status
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) setCompatibilityStatusByErr(err error) {
|
||||||
|
var status NetworkCompatibilityStatus
|
||||||
|
|
||||||
|
switch err {
|
||||||
|
case nil:
|
||||||
|
status = NetworkCompatibilityStatusOk
|
||||||
|
case handshake.ErrIncompatibleVersion:
|
||||||
|
status = NetworkCompatibilityStatusIncompatible
|
||||||
|
case net.ErrUnableToConnect:
|
||||||
|
status = NetworkCompatibilityStatusUnknown
|
||||||
|
default:
|
||||||
|
status = NetworkCompatibilityStatusError
|
||||||
|
}
|
||||||
|
|
||||||
|
s.setCompatibilityStatus(status)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) setLastConfiguration(c Configuration) (err error) {
|
func (s *service) setLastConfiguration(c Configuration) (err error) {
|
||||||
|
@ -137,21 +197,6 @@ func (s *service) setLastConfiguration(c Configuration) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) setCompatibilityStatusByErr(err error) {
|
|
||||||
s.mu.Lock()
|
|
||||||
defer s.mu.Unlock()
|
|
||||||
switch err {
|
|
||||||
case nil:
|
|
||||||
s.compatibilityStatus = NetworkCompatibilityStatusOk
|
|
||||||
case handshake.ErrIncompatibleVersion:
|
|
||||||
s.compatibilityStatus = NetworkCompatibilityStatusIncompatible
|
|
||||||
case net.ErrUnableToConnect:
|
|
||||||
s.compatibilityStatus = NetworkCompatibilityStatusUnknown
|
|
||||||
default:
|
|
||||||
s.compatibilityStatus = NetworkCompatibilityStatusError
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *service) Id() string {
|
func (s *service) Id() string {
|
||||||
s.mu.RLock()
|
s.mu.RLock()
|
||||||
defer s.mu.RUnlock()
|
defer s.mu.RUnlock()
|
||||||
|
|
|
@ -54,26 +54,44 @@ func TestService_NetworkCompatibilityStatus(t *testing.T) {
|
||||||
time.Sleep(time.Millisecond * 10)
|
time.Sleep(time.Millisecond * 10)
|
||||||
assert.Equal(t, NetworkCompatibilityStatusOk, fx.NetworkCompatibilityStatus())
|
assert.Equal(t, NetworkCompatibilityStatusOk, fx.NetworkCompatibilityStatus())
|
||||||
})
|
})
|
||||||
|
t.Run("needs update", func(t *testing.T) {
|
||||||
|
fx := newFixture(t)
|
||||||
|
fx.testCoordinator.needsUpdate = true
|
||||||
|
defer fx.finish(t)
|
||||||
|
fx.run(t)
|
||||||
|
time.Sleep(time.Millisecond * 10)
|
||||||
|
assert.Equal(t, NetworkCompatibilityStatusNeedsUpdate, fx.NetworkCompatibilityStatus())
|
||||||
|
})
|
||||||
|
t.Run("network not changed update", func(t *testing.T) {
|
||||||
|
fx := newFixture(t)
|
||||||
|
fx.testSource.err = ErrConfigurationNotChanged
|
||||||
|
defer fx.finish(t)
|
||||||
|
fx.run(t)
|
||||||
|
time.Sleep(time.Millisecond * 10)
|
||||||
|
assert.Equal(t, NetworkCompatibilityStatusOk, fx.NetworkCompatibilityStatus())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFixture(t *testing.T) *fixture {
|
func newFixture(t *testing.T) *fixture {
|
||||||
fx := &fixture{
|
fx := &fixture{
|
||||||
Service: New(),
|
Service: New(),
|
||||||
a: new(app.App),
|
testCoordinator: &testCoordinator{},
|
||||||
testStore: &testStore{},
|
a: new(app.App),
|
||||||
testSource: &testSource{},
|
testStore: &testStore{},
|
||||||
testConf: newTestConf(),
|
testSource: &testSource{},
|
||||||
|
testConf: newTestConf(),
|
||||||
}
|
}
|
||||||
fx.a.Register(fx.testConf).Register(&accounttest.AccountTestService{}).Register(fx.Service).Register(fx.testSource).Register(fx.testStore)
|
fx.a.Register(fx.testConf).Register(&accounttest.AccountTestService{}).Register(fx.Service).Register(fx.testSource).Register(fx.testStore).Register(fx.testCoordinator)
|
||||||
return fx
|
return fx
|
||||||
}
|
}
|
||||||
|
|
||||||
type fixture struct {
|
type fixture struct {
|
||||||
Service
|
Service
|
||||||
a *app.App
|
a *app.App
|
||||||
testStore *testStore
|
testStore *testStore
|
||||||
testSource *testSource
|
testSource *testSource
|
||||||
testConf *testConf
|
testConf *testConf
|
||||||
|
testCoordinator *testCoordinator
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fx *fixture) run(t *testing.T) {
|
func (fx *fixture) run(t *testing.T) {
|
||||||
|
@ -84,6 +102,17 @@ func (fx *fixture) finish(t *testing.T) {
|
||||||
require.NoError(t, fx.a.Close(ctx))
|
require.NoError(t, fx.a.Close(ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type testCoordinator struct {
|
||||||
|
needsUpdate bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *testCoordinator) IsNetworkNeedsUpdate(ctx context.Context) (bool, error) {
|
||||||
|
return t.needsUpdate, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *testCoordinator) Init(a *app.App) error { return nil }
|
||||||
|
func (t *testCoordinator) Name() string { return "testCoordinator" }
|
||||||
|
|
||||||
type testSource struct {
|
type testSource struct {
|
||||||
conf Configuration
|
conf Configuration
|
||||||
err error
|
err error
|
||||||
|
|
|
@ -57,8 +57,7 @@ func New() AnyPpClientService {
|
||||||
func (s *service) doClient(ctx context.Context, fn func(cl pp.DRPCAnyPaymentProcessingClient) error) error {
|
func (s *service) doClient(ctx context.Context, fn func(cl pp.DRPCAnyPaymentProcessingClient) error) error {
|
||||||
if len(s.nodeconf.PaymentProcessingNodePeers()) == 0 {
|
if len(s.nodeconf.PaymentProcessingNodePeers()) == 0 {
|
||||||
log.Error("no payment processing peers configured")
|
log.Error("no payment processing peers configured")
|
||||||
|
return errors.New("no paymentProcessingNode peers configured. Node config ID: " + s.nodeconf.Id())
|
||||||
return errors.New("no paymentProcessingNode peers configured")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// it will try to connect to the Payment Node
|
// it will try to connect to the Payment Node
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue