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))
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
@ -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 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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/mock/gomock"
|
||||
|
@ -18,6 +17,7 @@ import (
|
|||
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
||||
"github.com/anyproto/any-sync/consensus/consensusproto"
|
||||
"github.com/anyproto/any-sync/net/peer"
|
||||
"github.com/anyproto/any-sync/net/rpc/rpctest"
|
||||
)
|
||||
|
||||
type pushSpaceRequestMatcher struct {
|
||||
|
@ -56,49 +56,6 @@ func (p pushSpaceRequestMatcher) String() string {
|
|||
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) {
|
||||
fx.init(t)
|
||||
fx.diffSyncer = newDiffSyncer(fx.headSync).(*diffSyncer)
|
||||
|
@ -116,7 +73,7 @@ func TestDiffSyncer(t *testing.T) {
|
|||
fx := newHeadSyncFixture(t)
|
||||
fx.initDiffSyncer(t)
|
||||
defer fx.stop()
|
||||
mPeer := mockPeer{}
|
||||
mPeer := rpctest.MockPeer{}
|
||||
remDiff := NewRemoteDiff(fx.spaceState.SpaceId, fx.clientMock)
|
||||
fx.aclMock.EXPECT().Id().AnyTimes().Return("aclId")
|
||||
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{"changed"}).Return([]string{"changed"}).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))
|
||||
})
|
||||
|
||||
|
@ -139,7 +96,7 @@ func TestDiffSyncer(t *testing.T) {
|
|||
fx := newHeadSyncFixture(t)
|
||||
fx.initDiffSyncer(t)
|
||||
defer fx.stop()
|
||||
mPeer := mockPeer{}
|
||||
mPeer := rpctest.MockPeer{}
|
||||
remDiff := NewRemoteDiff(fx.spaceState.SpaceId, fx.clientMock)
|
||||
fx.treeSyncerMock.EXPECT().ShouldSync(gomock.Any()).Return(true)
|
||||
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{"changed"}).Return([]string{"changed", "aclId"}).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.aclMock.EXPECT().SyncWithPeer(gomock.Any(), mPeer.Id()).Return(nil)
|
||||
fx.treeSyncerMock.EXPECT().SyncAll(gomock.Any(), mPeer, []string{"changed"}, []string{"new"}).Return(nil)
|
||||
fx.aclMock.EXPECT().SyncWithPeer(gomock.Any(), mPeer).Return(nil)
|
||||
require.NoError(t, fx.diffSyncer.Sync(ctx))
|
||||
})
|
||||
|
||||
|
@ -225,7 +182,7 @@ func TestDiffSyncer(t *testing.T) {
|
|||
|
||||
fx.peerManagerMock.EXPECT().
|
||||
GetResponsiblePeers(gomock.Any()).
|
||||
Return([]peer.Peer{mockPeer{}}, nil)
|
||||
Return([]peer.Peer{rpctest.MockPeer{}}, nil)
|
||||
fx.diffContainerMock.EXPECT().
|
||||
DiffTypeCheck(gomock.Any(), gomock.Eq(remDiff)).Return(true, fx.diffMock, nil)
|
||||
fx.diffMock.EXPECT().
|
||||
|
@ -261,7 +218,7 @@ func TestDiffSyncer(t *testing.T) {
|
|||
fx.treeSyncerMock.EXPECT().ShouldSync(gomock.Any()).Return(true)
|
||||
fx.peerManagerMock.EXPECT().
|
||||
GetResponsiblePeers(gomock.Any()).
|
||||
Return([]peer.Peer{mockPeer{}}, nil)
|
||||
Return([]peer.Peer{rpctest.MockPeer{}}, nil)
|
||||
fx.diffContainerMock.EXPECT().
|
||||
DiffTypeCheck(gomock.Any(), gomock.Eq(remDiff)).Return(true, fx.diffMock, nil)
|
||||
fx.diffMock.EXPECT().
|
||||
|
@ -275,7 +232,7 @@ func TestDiffSyncer(t *testing.T) {
|
|||
fx := newHeadSyncFixture(t)
|
||||
fx.initDiffSyncer(t)
|
||||
defer fx.stop()
|
||||
mPeer := mockPeer{}
|
||||
mPeer := rpctest.MockPeer{}
|
||||
remDiff := NewRemoteDiff(fx.spaceState.SpaceId, fx.clientMock)
|
||||
fx.treeSyncerMock.EXPECT().ShouldSync(gomock.Any()).Return(true)
|
||||
fx.aclMock.EXPECT().Id().AnyTimes().Return("aclId")
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
headupdater "github.com/anyproto/any-sync/commonspace/object/acl/syncacl/headupdater"
|
||||
spacesyncproto "github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
||||
consensusproto "github.com/anyproto/any-sync/consensus/consensusproto"
|
||||
peer "github.com/anyproto/any-sync/net/peer"
|
||||
crypto "github.com/anyproto/any-sync/util/crypto"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
)
|
||||
|
@ -132,17 +133,17 @@ func (mr *MockSyncAclMockRecorder) GetIndex(arg0 any) *gomock.Call {
|
|||
}
|
||||
|
||||
// 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()
|
||||
ret := m.ctrl.Call(m, "HandleMessage", arg0, arg1, arg2)
|
||||
ret := m.ctrl.Call(m, "HandleMessage", arg0, arg1, arg2, arg3)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// 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()
|
||||
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.
|
||||
|
@ -430,7 +431,7 @@ func (mr *MockSyncAclMockRecorder) SetHeadUpdater(arg0 any) *gomock.Call {
|
|||
}
|
||||
|
||||
// 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()
|
||||
ret := m.ctrl.Call(m, "SyncWithPeer", arg0, arg1)
|
||||
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)
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (m *MockSyncClient) CreateFullSyncRequest(arg0 list.AclList, arg1 string) (*consensusproto.LogSyncMessage, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
@ -614,6 +629,20 @@ func (m *MockRequestFactory) EXPECT() *MockRequestFactoryMockRecorder {
|
|||
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.
|
||||
func (m *MockRequestFactory) CreateFullSyncRequest(arg0 list.AclList, arg1 string) (*consensusproto.LogSyncMessage, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
|
||||
type RequestFactory interface {
|
||||
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)
|
||||
CreateFullSyncResponse(l list.AclList, theirHead string) (*consensusproto.LogSyncMessage, error)
|
||||
}
|
||||
|
@ -26,6 +27,13 @@ func (r *requestFactory) CreateHeadUpdate(l list.AclList, added []*consensusprot
|
|||
}, 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) {
|
||||
if !l.HasHead(theirHead) {
|
||||
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/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/app"
|
||||
|
@ -35,7 +37,7 @@ type SyncAcl interface {
|
|||
list.AclList
|
||||
syncobjectgetter.SyncObject
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -73,8 +75,8 @@ func (s *syncAcl) SetHeadUpdater(updater headupdater.HeadUpdater) {
|
|||
s.headUpdater = updater
|
||||
}
|
||||
|
||||
func (s *syncAcl) HandleMessage(ctx context.Context, senderId string, request *spacesyncproto.ObjectSyncMessage) (err error) {
|
||||
return s.syncHandler.HandleMessage(ctx, senderId, request)
|
||||
func (s *syncAcl) HandleMessage(ctx context.Context, senderId string, protoVersion uint32, request *spacesyncproto.ObjectSyncMessage) (err error) {
|
||||
return s.syncHandler.HandleMessage(ctx, senderId, protoVersion, request)
|
||||
}
|
||||
|
||||
func (s *syncAcl) Init(a *app.App) (err error) {
|
||||
|
@ -136,11 +138,18 @@ func (s *syncAcl) AddRawRecords(rawRecords []*consensusproto.RawRecordWithId) (e
|
|||
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()
|
||||
defer s.Unlock()
|
||||
protoVersion, err := peer.CtxProtoVersion(p.Context())
|
||||
// this works with old protocol
|
||||
if err != nil || protoVersion <= secureservice.ProtoVersion {
|
||||
headUpdate := s.syncClient.CreateHeadUpdate(s, nil)
|
||||
return s.syncClient.SendUpdate(peerId, headUpdate)
|
||||
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) {
|
||||
|
|
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"
|
||||
"errors"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
|
||||
"github.com/anyproto/any-sync/commonspace/object/acl/list"
|
||||
"github.com/anyproto/any-sync/commonspace/objectsync/synchandler"
|
||||
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
||||
"github.com/anyproto/any-sync/commonspace/syncstatus"
|
||||
"github.com/anyproto/any-sync/consensus/consensusproto"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/anyproto/any-sync/net/secureservice"
|
||||
)
|
||||
|
||||
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{}
|
||||
err = proto.Unmarshal(message.Payload, unmarshalled)
|
||||
if err != nil {
|
||||
|
@ -57,7 +59,18 @@ func (s *syncAclHandler) HandleMessage(ctx context.Context, senderId string, mes
|
|||
case content.GetFullSyncRequest() != nil:
|
||||
return ErrMessageIsRequest
|
||||
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
|
||||
}
|
||||
|
|
|
@ -3,16 +3,20 @@ package syncacl
|
|||
import (
|
||||
"context"
|
||||
"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/syncacl/mock_syncacl"
|
||||
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
||||
"github.com/anyproto/any-sync/commonspace/syncstatus"
|
||||
"github.com/anyproto/any-sync/consensus/consensusproto"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/mock/gomock"
|
||||
"sync"
|
||||
"testing"
|
||||
"github.com/anyproto/any-sync/net/secureservice"
|
||||
)
|
||||
|
||||
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.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)
|
||||
})
|
||||
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.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)
|
||||
})
|
||||
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")
|
||||
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)
|
||||
})
|
||||
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)
|
||||
|
||||
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)
|
||||
})
|
||||
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.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)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
var (
|
||||
beforeId = params.BeforeId
|
||||
include = params.IncludeBeforeId
|
||||
full = params.BuildFullTree
|
||||
)
|
||||
h.treeBuilder.Reset()
|
||||
if full {
|
||||
|
||||
if len(params.Heads) == 0 {
|
||||
h.tree, err = h.treeBuilder.BuildFull()
|
||||
return
|
||||
}
|
||||
if beforeId == h.Id() && !include {
|
||||
return ErrLoadBeforeRoot
|
||||
return err
|
||||
}
|
||||
|
||||
heads := []string{beforeId}
|
||||
if beforeId == "" {
|
||||
heads, err = h.treeStorage.Heads()
|
||||
if err != nil {
|
||||
return
|
||||
if len(params.Heads) == 1 {
|
||||
return h.rebuildWithSingleHead(params.IncludeBeforeId, params.Heads[0])
|
||||
}
|
||||
} else if !include {
|
||||
beforeChange, err := h.treeBuilder.loadChange(beforeId)
|
||||
|
||||
h.tree, err = h.treeBuilder.build(params.Heads, nil, nil)
|
||||
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
|
||||
}
|
||||
heads = beforeChange.PreviousIds
|
||||
}
|
||||
|
||||
h.tree, err = h.treeBuilder.build(heads, nil, nil)
|
||||
return
|
||||
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"})
|
||||
hTree, err := buildHistoryTree(deps, HistoryTreeParams{
|
||||
BeforeId: "6",
|
||||
Heads: []string{"6"},
|
||||
IncludeBeforeId: false,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
@ -1276,9 +1276,7 @@ func TestObjectTree(t *testing.T) {
|
|||
changeCreator.CreateRaw("6", aclList.Head().Id, "5", false, "5"),
|
||||
}
|
||||
deps.treeStorage.AddRawChangesSetHeads(rawChanges, []string{"6"})
|
||||
hTree, err := buildHistoryTree(deps, HistoryTreeParams{
|
||||
BuildFullTree: true,
|
||||
})
|
||||
hTree, err := buildHistoryTree(deps, HistoryTreeParams{})
|
||||
require.NoError(t, err)
|
||||
// check tree heads
|
||||
assert.Equal(t, []string{"6"}, hTree.Heads())
|
||||
|
@ -1307,8 +1305,7 @@ func TestObjectTree(t *testing.T) {
|
|||
}
|
||||
deps.treeStorage.AddRawChangesSetHeads(rawChanges, []string{"6"})
|
||||
hTree, err := buildHistoryTree(deps, HistoryTreeParams{
|
||||
BeforeId: "6",
|
||||
IncludeBeforeId: true,
|
||||
Heads: []string{"6"}, IncludeBeforeId: true,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
// check tree heads
|
||||
|
@ -1328,7 +1325,7 @@ func TestObjectTree(t *testing.T) {
|
|||
t.Run("test history tree root", func(t *testing.T) {
|
||||
_, deps := prepareHistoryTreeDeps(aclList)
|
||||
hTree, err := buildHistoryTree(deps, HistoryTreeParams{
|
||||
BeforeId: "0",
|
||||
Heads: []string{"0"},
|
||||
IncludeBeforeId: true,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
|
|
@ -27,9 +27,8 @@ type ObjectTreeDerivePayload struct {
|
|||
type HistoryTreeParams struct {
|
||||
TreeStorage treestorage.TreeStorage
|
||||
AclList list.AclList
|
||||
BeforeId string
|
||||
Heads []string
|
||||
IncludeBeforeId bool
|
||||
BuildFullTree bool
|
||||
}
|
||||
|
||||
type objectTreeDeps struct {
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
treechangeproto "github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
|
||||
treestorage "github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
|
||||
spacesyncproto "github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
||||
peer "github.com/anyproto/any-sync/net/peer"
|
||||
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)
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (m *MockSyncTree) ChangeInfo() *treechangeproto.TreeChangeInfo {
|
||||
m.ctrl.T.Helper()
|
||||
|
@ -207,17 +223,17 @@ func (mr *MockSyncTreeMockRecorder) GetChange(arg0 any) *gomock.Call {
|
|||
}
|
||||
|
||||
// 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()
|
||||
ret := m.ctrl.Call(m, "HandleMessage", arg0, arg1, arg2)
|
||||
ret := m.ctrl.Call(m, "HandleMessage", arg0, arg1, arg2, arg3)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// 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()
|
||||
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.
|
||||
|
@ -445,7 +461,7 @@ func (mr *MockSyncTreeMockRecorder) Storage() *gomock.Call {
|
|||
}
|
||||
|
||||
// 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()
|
||||
ret := m.ctrl.Call(m, "SyncWithPeer", arg0, arg1)
|
||||
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)
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (m *MockSyncClient) CreateFullSyncRequest(arg0 objecttree.ObjectTree, arg1, arg2 []string) (*treechangeproto.TreeSyncMessage, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
@ -787,6 +817,20 @@ func (m *MockRequestFactory) EXPECT() *MockRequestFactoryMockRecorder {
|
|||
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.
|
||||
func (m *MockRequestFactory) CreateFullSyncRequest(arg0 objecttree.ObjectTree, arg1, arg2 []string) (*treechangeproto.TreeSyncMessage, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
@ -898,16 +942,16 @@ func (mr *MockTreeSyncProtocolMockRecorder) FullSyncResponse(arg0, arg1, arg2 an
|
|||
}
|
||||
|
||||
// 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()
|
||||
ret := m.ctrl.Call(m, "HeadUpdate", arg0, arg1, arg2)
|
||||
ret := m.ctrl.Call(m, "HeadUpdate", arg0, arg1, arg2, arg3)
|
||||
ret0, _ := ret[0].(*treechangeproto.TreeSyncMessage)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// 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()
|
||||
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 (
|
||||
"fmt"
|
||||
|
||||
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
|
||||
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
|
||||
"github.com/anyproto/any-sync/util/slice"
|
||||
|
@ -10,6 +11,7 @@ import (
|
|||
type RequestFactory interface {
|
||||
CreateHeadUpdate(t objecttree.ObjectTree, added []*treechangeproto.RawTreeChangeWithId) (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)
|
||||
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)
|
||||
}
|
||||
|
||||
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) {
|
||||
req := &treechangeproto.TreeFullSyncRequest{}
|
||||
if t == nil {
|
||||
|
|
|
@ -4,6 +4,7 @@ package synctree
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
@ -18,7 +19,9 @@ import (
|
|||
"github.com/anyproto/any-sync/commonspace/spacestorage"
|
||||
"github.com/anyproto/any-sync/commonspace/syncstatus"
|
||||
"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/util/slice"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -34,11 +37,16 @@ type ListenerSetter interface {
|
|||
SetListener(listener updatelistener.UpdateListener)
|
||||
}
|
||||
|
||||
type SyncTree interface {
|
||||
type peerSendableObjectTree interface {
|
||||
objecttree.ObjectTree
|
||||
AddRawChangesFromPeer(ctx context.Context, peerId string, changesPayload objecttree.RawChangesPayload) (res objecttree.AddResult, err error)
|
||||
}
|
||||
|
||||
type SyncTree interface {
|
||||
peerSendableObjectTree
|
||||
synchandler.SyncHandler
|
||||
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
|
||||
|
@ -79,13 +87,13 @@ type BuildDeps struct {
|
|||
func BuildSyncTreeOrGetRemote(ctx context.Context, id string, deps BuildDeps) (t SyncTree, err error) {
|
||||
var (
|
||||
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 {
|
||||
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) {
|
||||
|
@ -93,10 +101,10 @@ func PutSyncTree(ctx context.Context, payload treestorage.TreeStorageCreatePaylo
|
|||
if err != nil {
|
||||
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)
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -118,10 +126,13 @@ func buildSyncTree(ctx context.Context, sendUpdate bool, deps BuildDeps) (t Sync
|
|||
syncTree.Unlock()
|
||||
|
||||
// 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)
|
||||
// send to everybody, because everybody should know that the node or client got new tree
|
||||
syncTree.syncClient.Broadcast(headUpdate)
|
||||
if peerId != peer.CtxResponsiblePeers {
|
||||
deps.SyncStatus.ObjectReceive(peerId, syncTree.Id(), syncTree.Heads())
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -166,6 +177,38 @@ func (s *syncTree) AddContentWithValidator(ctx context.Context, content objecttr
|
|||
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) {
|
||||
if err = s.checkAlive(); err != nil {
|
||||
return
|
||||
|
@ -251,14 +294,21 @@ func (s *syncTree) checkAlive() (err error) {
|
|||
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()
|
||||
defer s.Unlock()
|
||||
if objecttree.IsEmptyDerivedTree(s) {
|
||||
return nil
|
||||
if objecttree.IsEmptyDerivedTree(s.ObjectTree) {
|
||||
return
|
||||
}
|
||||
protoVersion, err := peer.CtxProtoVersion(p.Context())
|
||||
// this works with old protocol
|
||||
if err != nil || protoVersion <= secureservice.ProtoVersion {
|
||||
headUpdate := s.syncClient.CreateHeadUpdate(s, nil)
|
||||
return s.syncClient.SendUpdate(peerId, headUpdate.RootChange.Id, headUpdate)
|
||||
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() {
|
||||
|
|
|
@ -60,7 +60,7 @@ func Test_BuildSyncTree(t *testing.T) {
|
|||
}
|
||||
|
||||
headUpdate := &treechangeproto.TreeSyncMessage{}
|
||||
t.Run("AddRawChanges update", func(t *testing.T) {
|
||||
t.Run("AddRawChangesFromPeer update", func(t *testing.T) {
|
||||
changes := []*treechangeproto.RawTreeChangeWithId{{Id: "some"}}
|
||||
payload := objecttree.RawChangesPayload{
|
||||
NewHeads: nil,
|
||||
|
@ -70,6 +70,8 @@ func Test_BuildSyncTree(t *testing.T) {
|
|||
Added: changes,
|
||||
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)).
|
||||
Return(expectedRes, nil)
|
||||
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().Broadcast(gomock.Eq(headUpdate))
|
||||
objTreeMock.EXPECT().Flush()
|
||||
res, err := tr.AddRawChanges(ctx, payload)
|
||||
res, err := tr.AddRawChangesFromPeer(ctx, "peerId", payload)
|
||||
require.NoError(t, err)
|
||||
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"}}
|
||||
payload := objecttree.RawChangesPayload{
|
||||
NewHeads: nil,
|
||||
|
@ -93,6 +95,7 @@ func Test_BuildSyncTree(t *testing.T) {
|
|||
Added: changes,
|
||||
Mode: objecttree.Rebuild,
|
||||
}
|
||||
objTreeMock.EXPECT().Heads().AnyTimes().Return([]string{"headId"})
|
||||
objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(payload)).
|
||||
Return(expectedRes, nil)
|
||||
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().Broadcast(gomock.Eq(headUpdate))
|
||||
objTreeMock.EXPECT().Flush()
|
||||
res, err := tr.AddRawChanges(ctx, payload)
|
||||
res, err := tr.AddRawChangesFromPeer(ctx, "peerId", payload)
|
||||
require.NoError(t, err)
|
||||
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"}}
|
||||
payload := objecttree.RawChangesPayload{
|
||||
NewHeads: nil,
|
||||
|
@ -115,10 +118,11 @@ func Test_BuildSyncTree(t *testing.T) {
|
|||
Added: changes,
|
||||
Mode: objecttree.Nothing,
|
||||
}
|
||||
objTreeMock.EXPECT().Heads().AnyTimes().Return([]string{"headId"})
|
||||
objTreeMock.EXPECT().AddRawChanges(gomock.Any(), gomock.Eq(payload)).
|
||||
Return(expectedRes, nil)
|
||||
|
||||
res, err := tr.AddRawChanges(ctx, payload)
|
||||
res, err := tr.AddRawChangesFromPeer(ctx, "peerId", payload)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectedRes, res)
|
||||
})
|
||||
|
|
|
@ -5,13 +5,15 @@ import (
|
|||
"errors"
|
||||
"sync"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
|
||||
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
|
||||
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
|
||||
"github.com/anyproto/any-sync/commonspace/objectsync/synchandler"
|
||||
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
||||
"github.com/anyproto/any-sync/commonspace/syncstatus"
|
||||
"github.com/anyproto/any-sync/net/secureservice"
|
||||
"github.com/anyproto/any-sync/util/slice"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -34,10 +36,10 @@ type syncTreeHandler struct {
|
|||
|
||||
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{
|
||||
objTree: objTree,
|
||||
syncProtocol: newTreeSyncProtocol(spaceId, objTree, syncClient),
|
||||
syncProtocol: newTreeSyncProtocol(spaceId, objTree, syncClient, syncStatus),
|
||||
syncClient: syncClient,
|
||||
syncStatus: syncStatus,
|
||||
spaceId: spaceId,
|
||||
|
@ -85,7 +87,7 @@ func (s *syncTreeHandler) handleRequest(ctx context.Context, senderId string, fu
|
|||
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{}
|
||||
err = proto.Unmarshal(msg.Payload, unmarshalled)
|
||||
if err != nil {
|
||||
|
@ -100,10 +102,10 @@ func (s *syncTreeHandler) HandleMessage(ctx context.Context, senderId string, ms
|
|||
return
|
||||
}
|
||||
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()
|
||||
defer s.objTree.Unlock()
|
||||
var (
|
||||
|
@ -129,7 +131,7 @@ func (s *syncTreeHandler) handleMessage(ctx context.Context, msg *treechangeprot
|
|||
switch {
|
||||
case content.GetHeadUpdate() != nil:
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
@ -137,7 +139,27 @@ func (s *syncTreeHandler) handleMessage(ctx context.Context, msg *treechangeprot
|
|||
case content.GetFullSyncRequest() != nil:
|
||||
return ErrMessageIsRequest
|
||||
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"
|
||||
"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/synctree/mock_synctree"
|
||||
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
|
||||
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
||||
"github.com/anyproto/any-sync/commonspace/syncstatus"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/mock/gomock"
|
||||
"github.com/anyproto/any-sync/net/secureservice"
|
||||
)
|
||||
|
||||
type testObjTreeMock struct {
|
||||
|
@ -19,6 +22,10 @@ type testObjTreeMock struct {
|
|||
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 {
|
||||
return &testObjTreeMock{
|
||||
MockObjectTree: mockTree,
|
||||
|
@ -111,10 +118,10 @@ func TestSyncTreeHandler_HandleMessage(t *testing.T) {
|
|||
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{"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)
|
||||
|
||||
err := fx.syncHandler.HandleMessage(ctx, fx.senderId, objectMsg)
|
||||
err := fx.syncHandler.HandleMessage(ctx, fx.senderId, 0, objectMsg)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []string{"h3"}, fx.syncHandler.heads)
|
||||
})
|
||||
|
@ -133,7 +140,7 @@ func TestSyncTreeHandler_HandleMessage(t *testing.T) {
|
|||
fx.syncHandler.heads = []string{"h1"}
|
||||
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)
|
||||
})
|
||||
|
||||
|
@ -152,9 +159,9 @@ func TestSyncTreeHandler_HandleMessage(t *testing.T) {
|
|||
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{"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.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().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)
|
||||
})
|
||||
|
||||
|
@ -195,7 +202,66 @@ func TestSyncTreeHandler_HandleMessage(t *testing.T) {
|
|||
fx.objectTreeMock.EXPECT().Heads().Times(2).Return([]string{"h3"})
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -60,16 +60,20 @@ func (t treeRemoteGetter) treeRequest(ctx context.Context, peerId string) (msg *
|
|||
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)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// 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)
|
||||
if err == nil {
|
||||
return
|
||||
|
@ -87,8 +91,7 @@ func (t treeRemoteGetter) getTree(ctx context.Context) (treeStorage treestorage.
|
|||
return
|
||||
}
|
||||
|
||||
isRemote = true
|
||||
resp, err := t.treeRequestLoop(ctx)
|
||||
resp, peerId, err := t.treeRequestLoop(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ func TestTreeRemoteGetter(t *testing.T) {
|
|||
fx.peerGetterMock.EXPECT().GetResponsiblePeers(tCtx).Return([]peer.Peer{mockPeer}, nil)
|
||||
fx.syncClientMock.EXPECT().CreateNewTreeRequest().Return(treeRequest)
|
||||
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.Equal(t, "id", resp.RootChange.Id)
|
||||
})
|
||||
|
@ -84,7 +84,7 @@ func TestTreeRemoteGetter(t *testing.T) {
|
|||
mockPeer.EXPECT().Id().AnyTimes().Return(peerId)
|
||||
fx.syncClientMock.EXPECT().CreateNewTreeRequest().Return(treeRequest)
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -3,15 +3,18 @@ package synctree
|
|||
import (
|
||||
"context"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/anyproto/any-sync/app/logger"
|
||||
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
|
||||
"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"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
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)
|
||||
FullSyncResponse(ctx context.Context, senderId string, response *treechangeproto.TreeFullSyncResponse) (err error)
|
||||
}
|
||||
|
@ -19,20 +22,22 @@ type TreeSyncProtocol interface {
|
|||
type treeSyncProtocol struct {
|
||||
log logger.CtxLogger
|
||||
spaceId string
|
||||
objTree objecttree.ObjectTree
|
||||
objTree peerSendableObjectTree
|
||||
syncStatus syncstatus.StatusUpdater
|
||||
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{
|
||||
log: log.With(zap.String("spaceId", spaceId), zap.String("treeId", objTree.Id())),
|
||||
spaceId: spaceId,
|
||||
objTree: objTree,
|
||||
syncStatus: syncStatus,
|
||||
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 (
|
||||
isEmptyUpdate = len(update.Changes) == 0
|
||||
objTree = t.objTree
|
||||
|
@ -62,6 +67,9 @@ func (t *treeSyncProtocol) HeadUpdate(ctx context.Context, senderId string, upda
|
|||
headEquals := slice.UnsortedEquals(objTree.Heads(), update.Heads)
|
||||
log.DebugCtx(ctx, "is empty update", zap.Bool("headEquals", headEquals))
|
||||
if headEquals {
|
||||
if protoVersion > secureservice.ProtoVersion {
|
||||
t.syncStatus.HeadsApply(senderId, objTree.Id(), update.Heads, true)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -70,11 +78,7 @@ func (t *treeSyncProtocol) HeadUpdate(ctx context.Context, senderId string, upda
|
|||
return
|
||||
}
|
||||
|
||||
if t.hasHeads(objTree, update.Heads) {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = objTree.AddRawChanges(ctx, objecttree.RawChangesPayload{
|
||||
_, err = objTree.AddRawChangesFromPeer(ctx, senderId, objecttree.RawChangesPayload{
|
||||
NewHeads: update.Heads,
|
||||
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) {
|
||||
_, err = objTree.AddRawChanges(ctx, objecttree.RawChangesPayload{
|
||||
if len(request.Changes) != 0 {
|
||||
_, err = objTree.AddRawChangesFromPeer(ctx, senderId, objecttree.RawChangesPayload{
|
||||
NewHeads: request.Heads,
|
||||
RawChanges: request.Changes,
|
||||
})
|
||||
|
@ -137,11 +141,8 @@ func (t *treeSyncProtocol) FullSyncResponse(ctx context.Context, senderId string
|
|||
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,
|
||||
RawChanges: response.Changes,
|
||||
})
|
||||
|
|
|
@ -3,14 +3,17 @@ package synctree
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/mock/gomock"
|
||||
|
||||
"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/mock_objecttree"
|
||||
"github.com/anyproto/any-sync/commonspace/object/tree/synctree/mock_synctree"
|
||||
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/mock/gomock"
|
||||
"testing"
|
||||
"github.com/anyproto/any-sync/commonspace/syncstatus"
|
||||
)
|
||||
|
||||
type treeSyncProtocolFixture struct {
|
||||
|
@ -32,7 +35,7 @@ func newSyncProtocolFixture(t *testing.T) *treeSyncProtocolFixture {
|
|||
spaceId := "spaceId"
|
||||
reqFactory := mock_synctree.NewMockRequestFactory(ctrl)
|
||||
objTree.EXPECT().Id().Return("treeId")
|
||||
syncProtocol := newTreeSyncProtocol(spaceId, objTree, reqFactory)
|
||||
syncProtocol := newTreeSyncProtocol(spaceId, objTree, reqFactory, syncstatus.NewNoOpSyncStatus())
|
||||
return &treeSyncProtocolFixture{
|
||||
log: log,
|
||||
spaceId: spaceId,
|
||||
|
@ -69,8 +72,7 @@ func TestTreeSyncProtocol_HeadUpdate(t *testing.T) {
|
|||
SnapshotPath: []string{"h1"},
|
||||
}
|
||||
fx.objectTreeMock.EXPECT().Id().AnyTimes().Return(fx.treeId)
|
||||
fx.objectTreeMock.EXPECT().Heads().Return([]string{"h2"}).Times(2)
|
||||
fx.objectTreeMock.EXPECT().HasChanges(gomock.Eq([]string{"h1"})).Return(false)
|
||||
fx.objectTreeMock.EXPECT().Heads().Return([]string{"h2"}).AnyTimes()
|
||||
fx.objectTreeMock.EXPECT().
|
||||
AddRawChanges(gomock.Any(), gomock.Eq(objecttree.RawChangesPayload{
|
||||
NewHeads: []string{"h1"},
|
||||
|
@ -79,7 +81,7 @@ func TestTreeSyncProtocol_HeadUpdate(t *testing.T) {
|
|||
Return(objecttree.AddResult{}, nil)
|
||||
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.Nil(t, res)
|
||||
})
|
||||
|
@ -96,8 +98,14 @@ func TestTreeSyncProtocol_HeadUpdate(t *testing.T) {
|
|||
|
||||
fx.objectTreeMock.EXPECT().Id().AnyTimes().Return(fx.treeId)
|
||||
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.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"})).
|
||||
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.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().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.Nil(t, res)
|
||||
})
|
||||
|
@ -161,7 +169,7 @@ func TestTreeSyncProtocol_FullSyncRequest(t *testing.T) {
|
|||
}
|
||||
|
||||
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().
|
||||
AddRawChanges(gomock.Any(), gomock.Eq(objecttree.RawChangesPayload{
|
||||
NewHeads: []string{"h1"},
|
||||
|
@ -190,6 +198,12 @@ func TestTreeSyncProtocol_FullSyncRequest(t *testing.T) {
|
|||
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)
|
||||
fx.reqFactory.EXPECT().
|
||||
CreateFullSyncResponse(gomock.Eq(fx.objectTreeMock), gomock.Eq([]string{"h1"}), gomock.Eq([]string{"h1"})).
|
||||
Return(fullResponse, nil)
|
||||
|
@ -228,7 +242,6 @@ func TestTreeSyncProtocol_FullSyncRequest(t *testing.T) {
|
|||
}
|
||||
|
||||
fx.objectTreeMock.EXPECT().Heads().Return([]string{"h2"}).AnyTimes()
|
||||
fx.objectTreeMock.EXPECT().HasChanges(gomock.Eq([]string{"h1"})).Return(false)
|
||||
fx.objectTreeMock.EXPECT().
|
||||
AddRawChanges(gomock.Any(), gomock.Eq(objecttree.RawChangesPayload{
|
||||
NewHeads: []string{"h1"},
|
||||
|
@ -258,9 +271,6 @@ func TestTreeSyncProtocol_FullSyncResponse(t *testing.T) {
|
|||
fx.objectTreeMock.EXPECT().
|
||||
Heads().
|
||||
Return([]string{"h2"}).AnyTimes()
|
||||
fx.objectTreeMock.EXPECT().
|
||||
HasChanges(gomock.Eq([]string{"h1"})).
|
||||
Return(false)
|
||||
fx.objectTreeMock.EXPECT().
|
||||
AddRawChanges(gomock.Any(), gomock.Eq(objecttree.RawChangesPayload{
|
||||
NewHeads: []string{"h1"},
|
||||
|
@ -286,6 +296,12 @@ func TestTreeSyncProtocol_FullSyncResponse(t *testing.T) {
|
|||
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)
|
||||
|
||||
err := fx.syncProtocol.FullSyncResponse(ctx, fx.senderId, fullSyncResponse)
|
||||
require.NoError(t, err)
|
||||
|
|
|
@ -3,6 +3,16 @@ package synctree
|
|||
import (
|
||||
"context"
|
||||
"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/commonspace/object/acl/list"
|
||||
"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/syncstatus"
|
||||
"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
|
||||
|
@ -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) {
|
||||
if h.SyncHandler != nil {
|
||||
return h.SyncHandler.HandleMessage(ctx, senderId, request)
|
||||
return h.SyncHandler.HandleMessage(ctx, senderId, 0, request)
|
||||
}
|
||||
unmarshalled := &treechangeproto.TreeSyncMessage{}
|
||||
err = proto.Unmarshal(request.Payload, unmarshalled)
|
||||
|
@ -317,6 +319,16 @@ func (b *broadcastTree) AddRawChanges(ctx context.Context, changes objecttree.Ra
|
|||
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 {
|
||||
changeCreator := objecttree.NewMockChangeCreator()
|
||||
st := changeCreator.CreateNewTreeStorage(treeId, aclList.Head().Id, false)
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
reflect "reflect"
|
||||
|
||||
app "github.com/anyproto/any-sync/app"
|
||||
peer "github.com/anyproto/any-sync/net/peer"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
|
@ -135,7 +136,7 @@ func (mr *MockTreeSyncerMockRecorder) StopSync() *gomock.Call {
|
|||
}
|
||||
|
||||
// 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()
|
||||
ret := m.ctrl.Call(m, "SyncAll", arg0, arg1, arg2, arg3)
|
||||
ret0, _ := ret[0].(error)
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"context"
|
||||
|
||||
"github.com/anyproto/any-sync/app"
|
||||
"github.com/anyproto/any-sync/net/peer"
|
||||
)
|
||||
|
||||
const CName = "common.object.treesyncer"
|
||||
|
@ -14,5 +15,5 @@ type TreeSyncer interface {
|
|||
StartSync()
|
||||
StopSync()
|
||||
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/metric"
|
||||
"github.com/anyproto/any-sync/net/peer"
|
||||
"github.com/anyproto/any-sync/net/secureservice"
|
||||
"github.com/anyproto/any-sync/util/multiqueue"
|
||||
|
||||
"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) {
|
||||
var err error
|
||||
peerProtoVersion, err := peer.CtxProtoVersion(msg.PeerCtx)
|
||||
if err != nil {
|
||||
peerProtoVersion = secureservice.ProtoVersion
|
||||
}
|
||||
msg.StartHandlingTime = time.Now()
|
||||
ctx := peer.CtxWithPeerId(context.Background(), 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
|
||||
}
|
||||
}
|
||||
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 != "" {
|
||||
// cleanup thread on error
|
||||
_ = 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)
|
||||
}
|
||||
|
||||
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))
|
||||
defer func() {
|
||||
if p := recover(); p != nil {
|
||||
|
@ -186,7 +191,7 @@ func (s *objectSync) handleMessage(ctx context.Context, senderId string, msg *sp
|
|||
if err != nil {
|
||||
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 {
|
||||
return fmt.Errorf("failed to handle message: %w", err)
|
||||
}
|
||||
|
|
|
@ -2,10 +2,11 @@ package synchandler
|
|||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -39,9 +39,8 @@ var log = logger.NewNamed(CName)
|
|||
var ErrSpaceClosed = errors.New("space is closed")
|
||||
|
||||
type HistoryTreeOpts struct {
|
||||
BeforeId string
|
||||
Heads []string
|
||||
Include bool
|
||||
BuildFullTree bool
|
||||
}
|
||||
|
||||
type TreeBuilder interface {
|
||||
|
@ -145,9 +144,8 @@ func (t *treeBuilder) BuildHistoryTree(ctx context.Context, id string, opts Hist
|
|||
|
||||
params := objecttree.HistoryTreeParams{
|
||||
AclList: t.aclList,
|
||||
BeforeId: opts.BeforeId,
|
||||
Heads: opts.Heads,
|
||||
IncludeBeforeId: opts.Include,
|
||||
BuildFullTree: opts.BuildFullTree,
|
||||
}
|
||||
params.TreeStorage, err = t.spaceStorage.TreeStorage(id)
|
||||
if err != nil {
|
||||
|
|
|
@ -13,7 +13,6 @@ import (
|
|||
"github.com/anyproto/any-sync/commonspace/objectsync"
|
||||
"github.com/anyproto/any-sync/commonspace/spacestate"
|
||||
"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/rpc/rpcerr"
|
||||
)
|
||||
|
@ -112,7 +111,11 @@ func (r *requestManager) SendRequest(ctx context.Context, peerId string, req *sp
|
|||
defer func() {
|
||||
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) {
|
||||
|
@ -142,27 +145,36 @@ var doRequestAndHandle = (*requestManager).requestAndHandle
|
|||
|
||||
func (r *requestManager) requestAndHandle(peerId string, req *spacesyncproto.ObjectSyncMessage) {
|
||||
ctx := r.ctx
|
||||
resp, err := r.doRequest(ctx, peerId, req)
|
||||
res, err := r.doRequest(ctx, peerId, req)
|
||||
if err != nil {
|
||||
log.Warn("failed to send request", zap.Error(err))
|
||||
return
|
||||
}
|
||||
ctx = peer.CtxWithPeerId(ctx, peerId)
|
||||
_ = r.handler.HandleMessage(ctx, objectsync.HandleMessage{
|
||||
SenderId: peerId,
|
||||
Message: resp,
|
||||
PeerCtx: ctx,
|
||||
Message: res.resp,
|
||||
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)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
res.peerCtx = pr.Context()
|
||||
err = pr.DoDrpc(ctx, func(conn drpc.Conn) error {
|
||||
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
|
||||
})
|
||||
err = rpcerr.Unwrap(err)
|
||||
|
|
|
@ -66,12 +66,14 @@ func TestRequestManager_SyncRequest(t *testing.T) {
|
|||
defer fx.stop()
|
||||
|
||||
peerId := "PeerId"
|
||||
peerCtx := peer.CtxWithPeerId(ctx, peerId)
|
||||
peerMock := mock_peer.NewMockPeer(fx.ctrl)
|
||||
conn := &drpcconn.Conn{}
|
||||
msg := &spacesyncproto.ObjectSyncMessage{}
|
||||
resp := &spacesyncproto.ObjectSyncMessage{}
|
||||
fx.peerPoolMock.EXPECT().Get(ctx, peerId).Return(peerMock, 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) {
|
||||
drpcHandler(conn)
|
||||
}).Return(nil)
|
||||
|
@ -86,12 +88,14 @@ func TestRequestManager_SyncRequest(t *testing.T) {
|
|||
ctx = fx.requestManager.ctx
|
||||
|
||||
peerId := "PeerId"
|
||||
peerCtx := peer.CtxWithPeerId(ctx, peerId)
|
||||
peerMock := mock_peer.NewMockPeer(fx.ctrl)
|
||||
conn := &drpcconn.Conn{}
|
||||
msg := &spacesyncproto.ObjectSyncMessage{}
|
||||
resp := &spacesyncproto.ObjectSyncMessage{}
|
||||
fx.peerPoolMock.EXPECT().Get(ctx, peerId).Return(peerMock, 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) {
|
||||
drpcHandler(conn)
|
||||
}).Return(nil)
|
||||
|
|
|
@ -46,7 +46,6 @@ var (
|
|||
return objecttree.BuildHistoryTree(objecttree.HistoryTreeParams{
|
||||
TreeStorage: objTree.Storage(),
|
||||
AclList: objTree.AclList(),
|
||||
BuildFullTree: true,
|
||||
})
|
||||
}
|
||||
)
|
||||
|
|
|
@ -298,7 +298,7 @@ func (m mockTreeSyncer) StartSync() {
|
|||
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
|
||||
}
|
||||
|
||||
|
@ -364,6 +364,10 @@ var _ coordinatorclient.CoordinatorClient = (*mockCoordinatorClient)(nil)
|
|||
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) {
|
||||
return nil
|
||||
}
|
||||
|
@ -424,6 +428,10 @@ func (m mockCoordinatorClient) AclGetRecords(ctx context.Context, spaceId, aclHe
|
|||
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) {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package syncstatus
|
|||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"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) 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) {
|
||||
}
|
||||
|
||||
|
|
|
@ -11,4 +11,6 @@ type StatusUpdater interface {
|
|||
|
||||
HeadsChange(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/pool"
|
||||
"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/util/cidutil"
|
||||
"github.com/anyproto/any-sync/util/crypto"
|
||||
|
@ -40,6 +41,7 @@ type CoordinatorClient interface {
|
|||
SpaceMakeShareable(ctx context.Context, spaceId string) (err error)
|
||||
SpaceMakeUnshareable(ctx context.Context, spaceId, aclId string) (err 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)
|
||||
|
||||
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
|
||||
|
||||
AclEventLog(ctx context.Context, accountId, lastRecordId string, limit int) (records []*coordinatorproto.AclEventLogRecord, err error)
|
||||
|
||||
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 {
|
||||
p, err := c.getPeer(ctx)
|
||||
if err != nil {
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
//
|
||||
// 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
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (m *MockCoordinatorClient) AclGetRecords(arg0 context.Context, arg1, arg2 string) ([]*consensusproto.RawRecordWithId, error) {
|
||||
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)
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (m *MockCoordinatorClient) Name() string {
|
||||
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)
|
||||
AclGetRecords(ctx context.Context, in *AclGetRecordsRequest) (*AclGetRecordsResponse, error)
|
||||
AccountLimitsSet(ctx context.Context, in *AccountLimitsSetRequest) (*AccountLimitsSetResponse, error)
|
||||
AclEventLog(ctx context.Context, in *AclEventLogRequest) (*AclEventLogResponse, error)
|
||||
}
|
||||
|
||||
type drpcCoordinatorClient struct {
|
||||
|
@ -192,6 +193,15 @@ func (c *drpcCoordinatorClient) AccountLimitsSet(ctx context.Context, in *Accoun
|
|||
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 {
|
||||
SpaceSign(context.Context, *SpaceSignRequest) (*SpaceSignResponse, error)
|
||||
SpaceStatusCheck(context.Context, *SpaceStatusCheckRequest) (*SpaceStatusCheckResponse, error)
|
||||
|
@ -207,6 +217,7 @@ type DRPCCoordinatorServer interface {
|
|||
AclAddRecord(context.Context, *AclAddRecordRequest) (*AclAddRecordResponse, error)
|
||||
AclGetRecords(context.Context, *AclGetRecordsRequest) (*AclGetRecordsResponse, error)
|
||||
AccountLimitsSet(context.Context, *AccountLimitsSetRequest) (*AccountLimitsSetResponse, error)
|
||||
AclEventLog(context.Context, *AclEventLogRequest) (*AclEventLogResponse, error)
|
||||
}
|
||||
|
||||
type DRPCCoordinatorUnimplementedServer struct{}
|
||||
|
@ -267,9 +278,13 @@ func (s *DRPCCoordinatorUnimplementedServer) AccountLimitsSet(context.Context, *
|
|||
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{}
|
||||
|
||||
func (DRPCCoordinatorDescription) NumMethods() int { return 14 }
|
||||
func (DRPCCoordinatorDescription) NumMethods() int { return 15 }
|
||||
|
||||
func (DRPCCoordinatorDescription) Method(n int) (string, drpc.Encoding, drpc.Receiver, interface{}, bool) {
|
||||
switch n {
|
||||
|
@ -399,6 +414,15 @@ func (DRPCCoordinatorDescription) Method(n int) (string, drpc.Encoding, drpc.Rec
|
|||
in1.(*AccountLimitsSetRequest),
|
||||
)
|
||||
}, 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:
|
||||
return "", nil, nil, nil, false
|
||||
}
|
||||
|
@ -631,3 +655,19 @@ func (x *drpcCoordinator_AccountLimitsSetStream) SendAndClose(m *AccountLimitsSe
|
|||
}
|
||||
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);
|
||||
// AccountLimitsSet sets limits to the account. Can be used only by a network config member
|
||||
rpc AccountLimitsSet(AccountLimitsSetRequest) returns (AccountLimitsSetResponse);
|
||||
|
||||
// EventLog gets the latest event log records
|
||||
rpc AclEventLog(AclEventLogRequest) returns (AclEventLogResponse);
|
||||
}
|
||||
|
||||
message SpaceSignRequest {
|
||||
|
@ -364,5 +367,39 @@ message AccountLimitsSetRequest {
|
|||
uint32 sharedSpacesLimit = 6;
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
return nodeconf.Configuration{
|
||||
Id: res.ConfigurationId,
|
||||
NetworkId: res.NetworkId,
|
||||
|
|
22
go.mod
22
go.mod
|
@ -12,7 +12,7 @@ require (
|
|||
github.com/cespare/xxhash v1.1.0
|
||||
github.com/cheggaaa/mb/v3 v3.0.2
|
||||
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/google/uuid v1.6.0
|
||||
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-cid v0.4.1
|
||||
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/multiformats/go-multibase v0.2.0
|
||||
github.com/multiformats/go-multihash v0.2.3
|
||||
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/tyler-smith/go-bip39 v1.1.0
|
||||
github.com/zeebo/blake3 v0.2.3
|
||||
go.uber.org/atomic v1.11.0
|
||||
go.uber.org/mock v0.4.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/net v0.25.0
|
||||
golang.org/x/net v0.28.0
|
||||
golang.org/x/time v0.5.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
storj.io/drpc v0.0.34
|
||||
|
@ -49,7 +49,7 @@ require (
|
|||
github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // 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/go-logr/logr v1.4.1 // 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/protobuf v1.5.4 // 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/go-bitfield v1.1.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/multiformats/go-base32 v0.1.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-multistream v0.5.0 // 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/pmezard/go-difflib v1.0.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/procfs v0.12.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/mod v0.17.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
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
google.golang.org/protobuf v1.34.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/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/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
|
||||
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 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg=
|
||||
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/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=
|
||||
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/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
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.2/go.mod h1:pMYpbAqJT10V8dzV1JN/g/wUlG/0imKPzn3ZsrchGCI=
|
||||
github.com/goccy/go-graphviz v0.1.3 h1:Pkt8y4FBnBNI9tfSobpoN5qy1qMNqRXPQYvLhaSUasY=
|
||||
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/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
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-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4=
|
||||
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.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||
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/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
|
||||
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/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/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI=
|
||||
github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
||||
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.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||
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/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-libp2p v0.33.2 h1:vCdwnFxoGOXMKmaGHlDSnL4bM3fQeW8pgIa9DECnb40=
|
||||
github.com/libp2p/go-libp2p v0.33.2/go.mod h1:zTeppLuCvUIkT118pFVzA8xzP/p2dJYOMApCkFh0Yww=
|
||||
github.com/libp2p/go-libp2p v0.35.1 h1:Hm7Ub2BF+GCb14ojcsEK6WAy5it5smPDK02iXSZLl50=
|
||||
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/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8=
|
||||
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-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-multiaddr v0.12.3 h1:hVBXvPRcKG0w80VinQ23P5t7czWgg65BmIvQKjDydU8=
|
||||
github.com/multiformats/go-multiaddr v0.12.3/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII=
|
||||
github.com/multiformats/go-multiaddr v0.12.4 h1:rrKqpY9h+n80EwhhC/kkcunCZZ7URIF8yN1WEUt2Hvc=
|
||||
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/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk=
|
||||
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.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
|
||||
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.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
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/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_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos=
|
||||
github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
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/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
|
||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||
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/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
||||
github.com/quic-go/quic-go v0.44.0 h1:So5wOr7jyO4vzL2sd8/pD9Kesciv91zSk8BoFngItQ0=
|
||||
github.com/quic-go/quic-go v0.44.0/go.mod h1:z4cx/9Ny9UtGITIPzmPTXh1ULfOyWh4qGQlpnPcWmek=
|
||||
github.com/quic-go/webtransport-go v0.6.0 h1:CvNsKqc4W2HljHJnoT+rMmbRJybShZ0YPFDD3NxaZLY=
|
||||
github.com/quic-go/webtransport-go v0.6.0/go.mod h1:9KjU4AEBqEQidGHNDkZrb8CAa1abRaosM2yGOyiikEc=
|
||||
github.com/quic-go/quic-go v0.46.0 h1:uuwLClEEyk1DNvchH8uCByQVjo3yKL9opKulExNDs7Y=
|
||||
github.com/quic-go/quic-go v0.46.0/go.mod h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI=
|
||||
github.com/quic-go/webtransport-go v0.8.0 h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv/cD7QFJg=
|
||||
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/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
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-20200602180216-279210d13fed/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.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
|
||||
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/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
|
||||
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-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.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
||||
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-20190423024810-112230192c58/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.5.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.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
|
||||
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/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.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
||||
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/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
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-20191204190536-9bdfabe68543/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.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||
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 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
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 {
|
||||
if len(s.nodeconf.NamingNodePeers()) == 0 {
|
||||
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
|
||||
|
|
|
@ -17,10 +17,12 @@ const (
|
|||
contextKeyIdentity
|
||||
contextKeyPeerAddr
|
||||
contextKeyPeerClientVersion
|
||||
contextKeyPeerProtoVersion
|
||||
)
|
||||
|
||||
var (
|
||||
ErrPeerIdNotFoundInContext = errors.New("peer id not found in context")
|
||||
ErrProtoVersionNotFoundInContext = errors.New("proto version not found in context")
|
||||
ErrIdentityNotFoundInContext = errors.New("identity not found in context")
|
||||
)
|
||||
|
||||
|
@ -42,6 +44,19 @@ func CtxWithPeerId(ctx context.Context, peerId string) context.Context {
|
|||
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
|
||||
func CtxPeerAddr(ctx context.Context) string {
|
||||
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 (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"storj.io/drpc"
|
||||
|
||||
"github.com/anyproto/any-sync/net/peer"
|
||||
"github.com/anyproto/any-sync/net/rpc/rpctest/multiconntest"
|
||||
"github.com/anyproto/any-sync/net/transport"
|
||||
|
@ -10,3 +14,50 @@ import (
|
|||
func MultiConnPair(peerIdServ, peerIdClient string) (serv, client transport.MultiConn) {
|
||||
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 2 - acl compatible version
|
||||
// ProtoVersion 3 - acl with breaking changes / multiplayer
|
||||
AclCompatibleVersion = uint32(2)
|
||||
ProtoVersion = uint32(3)
|
||||
NewSyncProtoVersion = uint32(4)
|
||||
)
|
||||
|
||||
var (
|
||||
compatibleVersions = []uint32{2, ProtoVersion}
|
||||
compatibleVersions = []uint32{AclCompatibleVersion, ProtoVersion, NewSyncProtoVersion}
|
||||
)
|
||||
|
||||
func New() SecureService {
|
||||
|
@ -119,6 +121,7 @@ func (s *secureService) HandshakeInbound(ctx context.Context, conn io.ReadWriteC
|
|||
cctx = peer.CtxWithPeerId(cctx, peerId)
|
||||
cctx = peer.CtxWithIdentity(cctx, res.Identity)
|
||||
cctx = peer.CtxWithClientVersion(cctx, res.ClientVersion)
|
||||
cctx = peer.CtxWithProtoVersion(cctx, res.ProtoVersion)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -146,6 +149,7 @@ func (s *secureService) HandshakeOutbound(ctx context.Context, conn io.ReadWrite
|
|||
cctx = peer.CtxWithPeerId(cctx, peerId)
|
||||
cctx = peer.CtxWithIdentity(cctx, res.Identity)
|
||||
cctx = peer.CtxWithClientVersion(cctx, res.ClientVersion)
|
||||
cctx = peer.CtxWithProtoVersion(cctx, res.ProtoVersion)
|
||||
return cctx, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/anyproto/any-sync/app/debugstat"
|
||||
"github.com/anyproto/any-sync/net"
|
||||
"github.com/anyproto/any-sync/net/peer"
|
||||
"github.com/anyproto/any-sync/net/secureservice"
|
||||
)
|
||||
|
||||
// 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
|
||||
ctx := peer.CtxWithPeerId(ctx, p.Id())
|
||||
// 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)
|
||||
if err != nil {
|
||||
op.err = err
|
||||
|
|
|
@ -3,6 +3,10 @@ package yamux
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/anyproto/any-sync/app"
|
||||
"github.com/anyproto/any-sync/app/logger"
|
||||
"github.com/anyproto/any-sync/net/connutil"
|
||||
|
@ -10,9 +14,6 @@ import (
|
|||
"github.com/anyproto/any-sync/net/transport"
|
||||
"github.com/hashicorp/yamux"
|
||||
"go.uber.org/zap"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const CName = "net.transport.yamux"
|
||||
|
@ -157,18 +158,18 @@ func (y *yamuxTransport) accept(conn net.Conn) {
|
|||
defer cancel()
|
||||
cctx, err := y.secure.SecureInbound(ctx, conn)
|
||||
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
|
||||
}
|
||||
luc := connutil.NewLastUsageConn(connutil.NewTimeout(conn, time.Duration(y.conf.WriteTimeoutSec)*time.Second))
|
||||
sess, err := yamux.Server(luc, y.yamuxConf)
|
||||
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
|
||||
}
|
||||
mc := NewMultiConn(cctx, luc, conn.RemoteAddr().String(), sess)
|
||||
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 {
|
||||
return
|
||||
}
|
||||
return os.WriteFile(path, data, 0755)
|
||||
return os.WriteFile(path, data, 0644)
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package nodeconf
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
commonaccount "github.com/anyproto/any-sync/accountservice"
|
||||
|
@ -31,6 +32,7 @@ const (
|
|||
NetworkCompatibilityStatusOk
|
||||
NetworkCompatibilityStatusError
|
||||
NetworkCompatibilityStatusIncompatible
|
||||
NetworkCompatibilityStatusNeedsUpdate
|
||||
)
|
||||
|
||||
func New() Service {
|
||||
|
@ -43,6 +45,10 @@ type Service interface {
|
|||
app.ComponentRunnable
|
||||
}
|
||||
|
||||
type NetworkProtoVersionChecker interface {
|
||||
IsNetworkNeedsUpdate(ctx context.Context) (bool, error)
|
||||
}
|
||||
|
||||
type service struct {
|
||||
accountId string
|
||||
config Configuration
|
||||
|
@ -53,6 +59,7 @@ type service struct {
|
|||
sync periodicsync.PeriodicSync
|
||||
|
||||
compatibilityStatus NetworkCompatibilityStatus
|
||||
networkProtoVersionChecker NetworkProtoVersionChecker
|
||||
}
|
||||
|
||||
func (s *service) Init(a *app.App) (err error) {
|
||||
|
@ -79,6 +86,7 @@ func (s *service) Init(a *app.App) (err error) {
|
|||
}
|
||||
return
|
||||
}, log)
|
||||
s.networkProtoVersionChecker = app.MustComponent[NetworkProtoVersionChecker](a)
|
||||
return s.setLastConfiguration(lastStored)
|
||||
}
|
||||
|
||||
|
@ -99,16 +107,68 @@ func (s *service) NetworkCompatibilityStatus() NetworkCompatibilityStatus {
|
|||
|
||||
func (s *service) updateConfiguration(ctx context.Context) (err error) {
|
||||
last, err := s.source.GetLast(ctx, s.Configuration().Id)
|
||||
if err != nil {
|
||||
if err != nil && !errors.Is(err, ErrConfigurationNotChanged) {
|
||||
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 {
|
||||
s.setCompatibilityStatusByErr(nil)
|
||||
s.setCompatibilityStatus(NetworkCompatibilityStatusOk)
|
||||
}
|
||||
if err = s.store.SaveLast(ctx, last); err != nil {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -137,21 +197,6 @@ func (s *service) setLastConfiguration(c Configuration) (err error) {
|
|||
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 {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
|
|
@ -54,17 +54,34 @@ func TestService_NetworkCompatibilityStatus(t *testing.T) {
|
|||
time.Sleep(time.Millisecond * 10)
|
||||
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 {
|
||||
fx := &fixture{
|
||||
Service: New(),
|
||||
testCoordinator: &testCoordinator{},
|
||||
a: new(app.App),
|
||||
testStore: &testStore{},
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -74,6 +91,7 @@ type fixture struct {
|
|||
testStore *testStore
|
||||
testSource *testSource
|
||||
testConf *testConf
|
||||
testCoordinator *testCoordinator
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
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 {
|
||||
conf Configuration
|
||||
err error
|
||||
|
|
|
@ -57,8 +57,7 @@ func New() AnyPpClientService {
|
|||
func (s *service) doClient(ctx context.Context, fn func(cl pp.DRPCAnyPaymentProcessingClient) error) error {
|
||||
if len(s.nodeconf.PaymentProcessingNodePeers()) == 0 {
|
||||
log.Error("no payment processing peers configured")
|
||||
|
||||
return errors.New("no paymentProcessingNode peers configured")
|
||||
return errors.New("no paymentProcessingNode peers configured. Node config ID: " + s.nodeconf.Id())
|
||||
}
|
||||
|
||||
// it will try to connect to the Payment Node
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue