diff --git a/commonspace/object/tree/synctree/synctreehandler.go b/commonspace/object/tree/synctree/synctreehandler.go index 7865f2a7..7b4cb2a8 100644 --- a/commonspace/object/tree/synctree/synctreehandler.go +++ b/commonspace/object/tree/synctree/synctreehandler.go @@ -167,7 +167,7 @@ func (s *syncTreeHandler) handleFullSyncRequest( defer func() { if err != nil { log.With(zap.Error(err)).DebugCtx(ctx, "full sync request finished with error") - s.syncClient.SendWithReply(ctx, senderId, treechangeproto.WrapError(treechangeproto.ErrorCodes_FullSyncRequestError, header), replyId) + s.syncClient.SendWithReply(ctx, senderId, treechangeproto.WrapError(treechangeproto.ErrFullSync, header), replyId) return } else if fullResponse != nil { cnt := fullResponse.Content.GetFullSyncResponse() diff --git a/commonspace/object/tree/treechangeproto/treechange.go b/commonspace/object/tree/treechangeproto/treechange.go index 0dc5d668..92ef3f16 100644 --- a/commonspace/object/tree/treechangeproto/treechange.go +++ b/commonspace/object/tree/treechangeproto/treechange.go @@ -1,5 +1,7 @@ package treechangeproto +import "github.com/anytypeio/any-sync/net/rpc/rpcerr" + func WrapHeadUpdate(update *TreeHeadUpdate, rootChange *RawTreeChangeWithId) *TreeSyncMessage { return &TreeSyncMessage{ Content: &TreeSyncContentValue{ @@ -27,10 +29,10 @@ func WrapFullResponse(response *TreeFullSyncResponse, rootChange *RawTreeChangeW } } -func WrapError(code ErrorCodes, rootChange *RawTreeChangeWithId) *TreeSyncMessage { +func WrapError(err error, rootChange *RawTreeChangeWithId) *TreeSyncMessage { return &TreeSyncMessage{ Content: &TreeSyncContentValue{ - Value: &TreeSyncContentValue_ErrorResponse{ErrorResponse: &TreeErrorResponse{ErrCode: uint64(code)}}, + Value: &TreeSyncContentValue_ErrorResponse{ErrorResponse: &TreeErrorResponse{ErrCode: rpcerr.Code(err)}}, }, RootChange: rootChange, } diff --git a/commonspace/objectsync/objectsync.go b/commonspace/objectsync/objectsync.go index 10075d34..e0f35893 100644 --- a/commonspace/objectsync/objectsync.go +++ b/commonspace/objectsync/objectsync.go @@ -84,18 +84,30 @@ func (s *objectSync) handleMessage(ctx context.Context, senderId string, msg *sp log = log.With(zap.Bool("isDeleted", true)) // preventing sync with other clients if they are not just syncing the settings tree if !slices.Contains(s.configuration.NodeIds(s.spaceId), senderId) && msg.ObjectId != s.spaceStorage.SpaceSettingsId() { - return spacesyncproto.ErrSpaceIsDeleted + return s.unmarshallSendError(ctx, msg, spacesyncproto.ErrSpaceIsDeleted, senderId) } } log.DebugCtx(ctx, "handling message") + hasTree, err := s.spaceStorage.HasTree(msg.ObjectId) + if err != nil { + return s.unmarshallSendError(ctx, msg, spacesyncproto.ErrUnexpected, senderId) + } + // in this case we will try to get it from remote, unless the sender also sent us the same request :-) + if !hasTree { + treeMsg := &treechangeproto.TreeSyncMessage{} + err = proto.Unmarshal(msg.Payload, treeMsg) + if err != nil { + return s.sendError(ctx, nil, spacesyncproto.ErrUnexpected, senderId, msg.ReplyId) + } + // this means that we don't have the tree locally and therefore can't return it + if s.isEmptyFullSyncRequest(treeMsg) { + return s.sendError(ctx, treeMsg.RootChange, treechangeproto.ErrGetTree, senderId, msg.ReplyId) + } + } obj, err := s.objectGetter.GetObject(ctx, msg.ObjectId) if err != nil { log.DebugCtx(ctx, "failed to get object") - respErr := s.sendErrorResponse(ctx, msg, senderId) - if respErr != nil { - log.DebugCtx(ctx, "failed to send error response", zap.Error(respErr)) - } - return + return s.unmarshallSendError(ctx, msg, err, senderId) } return obj.HandleMessage(ctx, senderId, msg) } @@ -104,12 +116,20 @@ func (s *objectSync) MessagePool() MessagePool { return s.messagePool } -func (s *objectSync) sendErrorResponse(ctx context.Context, msg *spacesyncproto.ObjectSyncMessage, senderId string) (err error) { +func (s *objectSync) unmarshallSendError(ctx context.Context, msg *spacesyncproto.ObjectSyncMessage, respErr error, senderId string) (err error) { unmarshalled := &treechangeproto.TreeSyncMessage{} err = proto.Unmarshal(msg.Payload, unmarshalled) if err != nil { return } - resp := treechangeproto.WrapError(treechangeproto.ErrorCodes_GetTreeError, unmarshalled.RootChange) - return s.syncClient.SendWithReply(ctx, senderId, resp, msg.ReplyId) + return s.sendError(ctx, unmarshalled.RootChange, respErr, senderId, msg.ReplyId) +} + +func (s *objectSync) sendError(ctx context.Context, root *treechangeproto.RawTreeChangeWithId, respErr error, senderId, replyId string) (err error) { + resp := treechangeproto.WrapError(respErr, root) + return s.syncClient.SendWithReply(ctx, senderId, resp, replyId) +} + +func (s *objectSync) isEmptyFullSyncRequest(msg *treechangeproto.TreeSyncMessage) bool { + return len(msg.GetContent().GetFullSyncRequest().GetHeads()) == 0 } diff --git a/commonspace/spacestorage/mock_spacestorage/mock_spacestorage.go b/commonspace/spacestorage/mock_spacestorage/mock_spacestorage.go index 82a14be2..93baa877 100644 --- a/commonspace/spacestorage/mock_spacestorage/mock_spacestorage.go +++ b/commonspace/spacestorage/mock_spacestorage/mock_spacestorage.go @@ -81,6 +81,21 @@ func (mr *MockSpaceStorageMockRecorder) CreateTreeStorage(arg0 interface{}) *gom return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateTreeStorage", reflect.TypeOf((*MockSpaceStorage)(nil).CreateTreeStorage), arg0) } +// HasTree mocks base method. +func (m *MockSpaceStorage) HasTree(arg0 string) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HasTree", arg0) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// HasTree indicates an expected call of HasTree. +func (mr *MockSpaceStorageMockRecorder) HasTree(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasTree", reflect.TypeOf((*MockSpaceStorage)(nil).HasTree), arg0) +} + // Id mocks base method. func (m *MockSpaceStorage) Id() string { m.ctrl.T.Helper() diff --git a/commonspace/spacestorage/spacestorage.go b/commonspace/spacestorage/spacestorage.go index ebd4b68d..3f21c22e 100644 --- a/commonspace/spacestorage/spacestorage.go +++ b/commonspace/spacestorage/spacestorage.go @@ -47,6 +47,7 @@ type SpaceStorage interface { StoredIds() ([]string, error) TreeRoot(id string) (*treechangeproto.RawTreeChangeWithId, error) TreeStorage(id string) (treestorage.TreeStorage, error) + HasTree(id string) (bool, error) CreateTreeStorage(payload treestorage.TreeStorageCreatePayload) (treestorage.TreeStorage, error) WriteSpaceHash(hash string) error ReadSpaceHash() (hash string, err error) diff --git a/net/rpc/rpcerr/registry.go b/net/rpc/rpcerr/registry.go index 5160fec3..e8a749e6 100644 --- a/net/rpc/rpcerr/registry.go +++ b/net/rpc/rpcerr/registry.go @@ -24,6 +24,10 @@ func RegisterErr(err error, code uint64) error { return errWithCode } +func Code(err error) uint64 { + return drpcerr.Code(err) +} + func Err(code uint64) error { err, ok := errsMap[code] if !ok {