diff --git a/app/ldiff/diff.go b/app/ldiff/diff.go index 0278037d..83b4c214 100644 --- a/app/ldiff/diff.go +++ b/app/ldiff/diff.go @@ -42,6 +42,11 @@ type Diff interface { DiffType() spacesyncproto.DiffType } +type CompareDiff interface { + CompareDiff(ctx context.Context, dl Remote) (newIds, ourChangedIds, theirChangedIds, removedIds []string, err error) + Diff +} + // New creates precalculated Diff container // // divideFactor - means how many hashes you want to ask for once @@ -273,17 +278,18 @@ func (d *diff) Ranges(ctx context.Context, ranges []Range, resBuf []RangeResult) } type diffCtx struct { - newIds, changedIds, removedIds []string + newIds, changedIds, theirChangedIds, removedIds []string toSend, prepare []Range myRes, otherRes []RangeResult + compareFunc func(dctx *diffCtx, my, other []Element) } var errMismatched = errors.New("query and results mismatched") // Diff makes diff with remote container func (d *diff) Diff(ctx context.Context, dl Remote) (newIds, changedIds, removedIds []string, err error) { - dctx := &diffCtx{} + dctx := &diffCtx{compareFunc: d.compareElementsEqual} dctx.toSend = append(dctx.toSend, Range{ From: 0, To: math.MaxUint64, @@ -314,18 +320,51 @@ func (d *diff) Diff(ctx context.Context, dl Remote) (newIds, changedIds, removed return dctx.newIds, dctx.changedIds, dctx.removedIds, nil } +func (d *diff) CompareDiff(ctx context.Context, dl Remote) (newIds, ourChangedIds, theirChangedIds, removedIds []string, err error) { + dctx := &diffCtx{compareFunc: d.compareElementsGreater} + dctx.toSend = append(dctx.toSend, Range{ + From: 0, + To: math.MaxUint64, + }) + for len(dctx.toSend) > 0 { + select { + case <-ctx.Done(): + err = ctx.Err() + return + default: + } + if dctx.otherRes, err = dl.Ranges(ctx, dctx.toSend, dctx.otherRes); err != nil { + return + } + if dctx.myRes, err = d.Ranges(ctx, dctx.toSend, dctx.myRes); err != nil { + return + } + if len(dctx.otherRes) != len(dctx.toSend) || len(dctx.myRes) != len(dctx.toSend) { + err = errMismatched + return + } + for i, r := range dctx.toSend { + d.compareResults(dctx, r, dctx.myRes[i], dctx.otherRes[i]) + } + dctx.toSend, dctx.prepare = dctx.prepare, dctx.toSend + dctx.prepare = dctx.prepare[:0] + } + return dctx.newIds, dctx.changedIds, dctx.theirChangedIds, dctx.removedIds, nil +} + func (d *diff) compareResults(dctx *diffCtx, r Range, myRes, otherRes RangeResult) { // both hash equals - do nothing if bytes.Equal(myRes.Hash, otherRes.Hash) { return } + // other has elements if len(otherRes.Elements) == otherRes.Count { if len(myRes.Elements) == myRes.Count { - d.compareElements(dctx, myRes.Elements, otherRes.Elements) + dctx.compareFunc(dctx, myRes.Elements, otherRes.Elements) } else { r.Elements = true - d.compareElements(dctx, d.getRange(r).Elements, otherRes.Elements) + dctx.compareFunc(dctx, d.getRange(r).Elements, otherRes.Elements) } return } @@ -341,7 +380,7 @@ func (d *diff) compareResults(dctx *diffCtx, r Range, myRes, otherRes RangeResul return } -func (d *diff) compareElements(dctx *diffCtx, my, other []Element) { +func (d *diff) compareElementsEqual(dctx *diffCtx, my, other []Element) { find := func(list []Element, targetEl Element) (has, eq bool) { for _, el := range list { if el.Id == targetEl.Id { @@ -369,3 +408,40 @@ func (d *diff) compareElements(dctx *diffCtx, my, other []Element) { } } } + +func (d *diff) compareElementsGreater(dctx *diffCtx, my, other []Element) { + find := func(list []Element, targetEl Element) (has, equal, greater bool) { + for _, el := range list { + if el.Id == targetEl.Id { + if el.Head == targetEl.Head { + return true, true, false + } + return true, false, el.Head > targetEl.Head + } + } + return false, false, false + } + + for _, el := range my { + has, eq, theirGreater := find(other, el) + if !has { + dctx.removedIds = append(dctx.removedIds, el.Id) + continue + } else { + if eq { + continue + } + if theirGreater { + dctx.theirChangedIds = append(dctx.theirChangedIds, el.Id) + } else { + dctx.changedIds = append(dctx.changedIds, el.Id) + } + } + } + + for _, el := range other { + if has, _, _ := find(my, el); !has { + dctx.newIds = append(dctx.newIds, el.Id) + } + } +} diff --git a/app/ldiff/diff_test.go b/app/ldiff/diff_test.go index d572647f..9e651526 100644 --- a/app/ldiff/diff_test.go +++ b/app/ldiff/diff_test.go @@ -139,6 +139,35 @@ func TestDiff_Diff(t *testing.T) { assert.Len(t, changedIds, length/2) assert.Len(t, removedIds, 0) }) + t.Run("compare diff", func(t *testing.T) { + d1 := New(16, 128).(CompareDiff) + d2 := New(16, 128) + + length := 10000 + for i := 0; i < length; i++ { + id := fmt.Sprint(i) + head := "a" + uuid.NewString() + d1.Set(Element{ + Id: id, + Head: head, + }) + } + for i := 0; i < length; i++ { + id := fmt.Sprint(i) + head := "b" + uuid.NewString() + d2.Set(Element{ + Id: id, + Head: head, + }) + } + + newIds, changedIds, theirChangedIds, removedIds, err := d1.CompareDiff(ctx, d2) + require.NoError(t, err) + assert.Len(t, newIds, 0) + assert.Len(t, changedIds, 0) + assert.Len(t, theirChangedIds, length) + assert.Len(t, removedIds, 0) + }) t.Run("empty", func(t *testing.T) { d1 := New(16, 16) d2 := New(16, 16) diff --git a/commonspace/deletion_test.go b/commonspace/deletion_test.go index b74d5798..add216a5 100644 --- a/commonspace/deletion_test.go +++ b/commonspace/deletion_test.go @@ -11,6 +11,7 @@ import ( "github.com/anyproto/any-sync/commonspace/object/accountdata" "github.com/anyproto/any-sync/commonspace/object/tree/objecttree" + "github.com/anyproto/any-sync/commonspace/spacepayloads" "github.com/anyproto/any-sync/commonspace/spacestorage" "github.com/anyproto/any-sync/commonspace/syncstatus" "github.com/anyproto/any-sync/util/crypto" @@ -47,7 +48,7 @@ func TestSpaceDeleteIdsMarkDeleted(t *testing.T) { totalObjs := 1000 // creating space - sp, err := fx.spaceService.CreateSpace(ctx, SpaceCreatePayload{ + sp, err := fx.spaceService.CreateSpace(ctx, spacepayloads.SpaceCreatePayload{ SigningKey: acc.SignKey, SpaceType: "type", ReadKey: rk, @@ -140,7 +141,7 @@ func TestSpaceDeleteIds(t *testing.T) { totalObjs := 1000 // creating space - sp, err := fx.spaceService.CreateSpace(ctx, SpaceCreatePayload{ + sp, err := fx.spaceService.CreateSpace(ctx, spacepayloads.SpaceCreatePayload{ SigningKey: acc.SignKey, SpaceType: "type", ReadKey: rk, diff --git a/commonspace/headsync/diffsyncer.go b/commonspace/headsync/diffsyncer.go index 79243356..a556f51c 100644 --- a/commonspace/headsync/diffsyncer.go +++ b/commonspace/headsync/diffsyncer.go @@ -8,6 +8,7 @@ import ( "github.com/quic-go/quic-go" "github.com/anyproto/any-sync/commonspace/headsync/headstorage" + "github.com/anyproto/any-sync/commonspace/object/keyvalue/kvinterfaces" "github.com/anyproto/any-sync/commonspace/object/treesyncer" "github.com/anyproto/any-sync/net/rpc/rpcerr" @@ -42,6 +43,7 @@ func newDiffSyncer(hs *headSync) DiffSyncer { peerManager: hs.peerManager, clientFactory: spacesyncproto.ClientFactoryFunc(spacesyncproto.NewDRPCSpaceSyncClient), credentialProvider: hs.credentialProvider, + keyValue: hs.keyValue, log: newSyncLogger(hs.log, logPeriodSecs), deletionState: hs.deletionState, syncAcl: hs.syncAcl, @@ -63,6 +65,7 @@ type diffSyncer struct { cancel context.CancelFunc deletionState deletionstate.ObjectDeletionState credentialProvider credentialprovider.CredentialProvider + keyValue kvinterfaces.KeyValueService syncAcl syncacl.SyncAcl } @@ -90,10 +93,17 @@ func (d *diffSyncer) updateHeads(update headstorage.HeadsUpdate) { if update.IsDerived != nil && *update.IsDerived && len(update.Heads) == 1 && update.Heads[0] == update.Id { return } - d.diffContainer.Set(ldiff.Element{ - Id: update.Id, - Head: concatStrings(update.Heads), - }) + if update.Id == d.keyValue.DefaultStore().Id() { + d.diffContainer.NewDiff().Set(ldiff.Element{ + Id: update.Id, + Head: concatStrings(update.Heads), + }) + } else { + d.diffContainer.Set(ldiff.Element{ + Id: update.Id, + Head: concatStrings(update.Heads), + }) + } } // probably we should somehow batch the updates oldHash := d.diffContainer.OldDiff().Hash() @@ -126,7 +136,6 @@ func (d *diffSyncer) Sync(ctx context.Context) error { } } d.log.DebugCtx(ctx, "diff done", zap.String("spaceId", d.spaceId), zap.Duration("dur", time.Since(st))) - d.peerManager.KeepAlive(ctx) return nil } @@ -153,6 +162,7 @@ func (d *diffSyncer) syncWithPeer(ctx context.Context, p peer.Peer) (err error) syncAclId = d.syncAcl.Id() newIds, changedIds, removedIds []string ) + storageId := d.keyValue.DefaultStore().Id() needsSync, diff, err := d.diffContainer.DiffTypeCheck(ctx, rdiff) err = rpcerr.Unwrap(err) if err != nil { @@ -169,17 +179,32 @@ func (d *diffSyncer) syncWithPeer(ctx context.Context, p peer.Peer) (err error) // not syncing ids which were removed through settings document missingIds := d.deletionState.Filter(newIds) existingIds := append(d.deletionState.Filter(removedIds), d.deletionState.Filter(changedIds)...) - - prevExistingLen := len(existingIds) + var ( + isStorage = false + isAcl = false + ) existingIds = slice.DiscardFromSlice(existingIds, func(s string) bool { - return s == syncAclId + if s == storageId { + isStorage = true + return true + } + if s == syncAclId { + isAcl = true + return true + } + return false }) // if we removed acl head from the list - if len(existingIds) < prevExistingLen { + if isAcl { if syncErr := d.syncAcl.SyncWithPeer(ctx, p); syncErr != nil { log.Warn("failed to send acl sync message to peer", zap.String("aclId", syncAclId)) } } + if isStorage { + if err = d.keyValue.SyncWithPeer(p); err != nil { + log.Warn("failed to send storage sync message to peer", zap.String("storageId", storageId)) + } + } // treeSyncer should not get acl id, that's why we filter existing ids before err = d.treeSyncer.SyncAll(ctx, p, existingIds, missingIds) diff --git a/commonspace/headsync/diffsyncer_test.go b/commonspace/headsync/diffsyncer_test.go index 6968b4f8..e9915670 100644 --- a/commonspace/headsync/diffsyncer_test.go +++ b/commonspace/headsync/diffsyncer_test.go @@ -118,6 +118,31 @@ func TestDiffSyncer(t *testing.T) { require.NoError(t, fx.diffSyncer.Sync(ctx)) }) + t.Run("diff syncer sync, store changed", func(t *testing.T) { + fx := newHeadSyncFixture(t) + fx.initDiffSyncer(t) + defer fx.stop() + 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") + fx.peerManagerMock.EXPECT(). + GetResponsiblePeers(gomock.Any()). + Return([]peer.Peer{mPeer}, nil) + fx.diffContainerMock.EXPECT().DiffTypeCheck(gomock.Any(), gomock.Any()).Return(true, fx.diffMock, nil) + fx.diffMock.EXPECT(). + Diff(gomock.Any(), gomock.Eq(remDiff)). + Return([]string{"new"}, []string{"changed"}, nil, nil) + fx.deletionStateMock.EXPECT().Filter([]string{"new"}).Return([]string{"new"}).Times(1) + fx.deletionStateMock.EXPECT().Filter([]string{"changed"}).Return([]string{"changed", "store"}).Times(1) + fx.deletionStateMock.EXPECT().Filter(nil).Return(nil).Times(1) + fx.treeSyncerMock.EXPECT().SyncAll(gomock.Any(), mPeer, []string{"changed"}, []string{"new"}).Return(nil) + fx.kvMock.EXPECT().SyncWithPeer(mPeer).Return(nil) + fx.peerManagerMock.EXPECT().KeepAlive(gomock.Any()) + + require.NoError(t, fx.diffSyncer.Sync(ctx)) + }) + t.Run("diff syncer sync conf error", func(t *testing.T) { fx := newHeadSyncFixture(t) fx.initDiffSyncer(t) diff --git a/commonspace/headsync/headsync.go b/commonspace/headsync/headsync.go index fd95e921..6c701c6b 100644 --- a/commonspace/headsync/headsync.go +++ b/commonspace/headsync/headsync.go @@ -16,6 +16,7 @@ import ( "github.com/anyproto/any-sync/commonspace/deletionstate" "github.com/anyproto/any-sync/commonspace/headsync/headstorage" "github.com/anyproto/any-sync/commonspace/object/acl/syncacl" + "github.com/anyproto/any-sync/commonspace/object/keyvalue/kvinterfaces" "github.com/anyproto/any-sync/commonspace/object/treesyncer" "github.com/anyproto/any-sync/commonspace/peermanager" "github.com/anyproto/any-sync/commonspace/spacestate" @@ -58,6 +59,7 @@ type headSync struct { credentialProvider credentialprovider.CredentialProvider deletionState deletionstate.ObjectDeletionState syncAcl syncacl.SyncAcl + keyValue kvinterfaces.KeyValueService } func New() HeadSync { @@ -80,6 +82,7 @@ func (h *headSync) Init(a *app.App) (err error) { h.credentialProvider = a.MustComponent(credentialprovider.CName).(credentialprovider.CredentialProvider) h.treeSyncer = a.MustComponent(treesyncer.CName).(treesyncer.TreeSyncer) h.deletionState = a.MustComponent(deletionstate.CName).(deletionstate.ObjectDeletionState) + h.keyValue = a.MustComponent(kvinterfaces.CName).(kvinterfaces.KeyValueService) h.syncer = createDiffSyncer(h) sync := func(ctx context.Context) (err error) { return h.syncer.Sync(ctx) @@ -117,8 +120,9 @@ func (h *headSync) AllIds() []string { func (h *headSync) ExternalIds() []string { settingsId := h.storage.StateStorage().SettingsId() aclId := h.syncAcl.Id() + keyValueId := h.keyValue.DefaultStore().Id() return slice.DiscardFromSlice(h.AllIds(), func(id string) bool { - return id == settingsId || id == aclId + return id == settingsId || id == aclId || id == keyValueId }) } @@ -130,14 +134,23 @@ func (h *headSync) Close(ctx context.Context) (err error) { func (h *headSync) fillDiff(ctx context.Context) error { var els = make([]ldiff.Element, 0, 100) + var aclOrStorage []ldiff.Element err := h.storage.HeadStorage().IterateEntries(ctx, headstorage.IterOpts{}, func(entry headstorage.HeadsEntry) (bool, error) { if entry.IsDerived && entry.Heads[0] == entry.Id { return true, nil } - els = append(els, ldiff.Element{ - Id: entry.Id, - Head: concatStrings(entry.Heads), - }) + if entry.CommonSnapshot != "" { + els = append(els, ldiff.Element{ + Id: entry.Id, + Head: concatStrings(entry.Heads), + }) + } else { + // this whole stuff is done to prevent storage hash from being set to old diff + aclOrStorage = append(aclOrStorage, ldiff.Element{ + Id: entry.Id, + Head: concatStrings(entry.Heads), + }) + } return true, nil }) if err != nil { @@ -149,6 +162,8 @@ func (h *headSync) fillDiff(ctx context.Context) error { }) log.Debug("setting acl", zap.String("aclId", h.syncAcl.Id()), zap.String("headId", h.syncAcl.Head().Id)) h.diffContainer.Set(els...) + // acl will be set twice to the diff but it doesn't matter + h.diffContainer.NewDiff().Set(aclOrStorage...) oldHash := h.diffContainer.OldDiff().Hash() newHash := h.diffContainer.NewDiff().Hash() if err := h.storage.StateStorage().SetHash(ctx, oldHash, newHash); err != nil { diff --git a/commonspace/headsync/headsync_test.go b/commonspace/headsync/headsync_test.go index 597b85e4..3ec4ee72 100644 --- a/commonspace/headsync/headsync_test.go +++ b/commonspace/headsync/headsync_test.go @@ -22,6 +22,9 @@ import ( "github.com/anyproto/any-sync/commonspace/object/acl/list" "github.com/anyproto/any-sync/commonspace/object/acl/syncacl" "github.com/anyproto/any-sync/commonspace/object/acl/syncacl/mock_syncacl" + "github.com/anyproto/any-sync/commonspace/object/keyvalue/keyvaluestorage/mock_keyvaluestorage" + "github.com/anyproto/any-sync/commonspace/object/keyvalue/kvinterfaces" + "github.com/anyproto/any-sync/commonspace/object/keyvalue/kvinterfaces/mock_kvinterfaces" "github.com/anyproto/any-sync/commonspace/object/treemanager" "github.com/anyproto/any-sync/commonspace/object/treemanager/mock_treemanager" "github.com/anyproto/any-sync/commonspace/object/treesyncer" @@ -34,6 +37,7 @@ import ( "github.com/anyproto/any-sync/commonspace/spacesyncproto/mock_spacesyncproto" "github.com/anyproto/any-sync/nodeconf" "github.com/anyproto/any-sync/nodeconf/mock_nodeconf" + "github.com/anyproto/any-sync/testutil/anymock" ) type mockConfig struct { @@ -57,6 +61,8 @@ type headSyncFixture struct { app *app.App configurationMock *mock_nodeconf.MockService + kvMock *mock_kvinterfaces.MockKeyValueService + defStoreMock *mock_keyvaluestorage.MockStorage storageMock *mock_spacestorage.MockSpaceStorage peerManagerMock *mock_peermanager.MockPeerManager credentialProviderMock *mock_credentialprovider.MockCredentialProvider @@ -96,6 +102,11 @@ func newHeadSyncFixture(t *testing.T) *headSyncFixture { treeSyncerMock := mock_treesyncer.NewMockTreeSyncer(ctrl) headStorage := mock_headstorage.NewMockHeadStorage(ctrl) stateStorage := mock_statestorage.NewMockStateStorage(ctrl) + kvMock := mock_kvinterfaces.NewMockKeyValueService(ctrl) + anymock.ExpectComp(kvMock.EXPECT(), kvinterfaces.CName) + defStore := mock_keyvaluestorage.NewMockStorage(ctrl) + kvMock.EXPECT().DefaultStore().Return(defStore).AnyTimes() + defStore.EXPECT().Id().Return("store").AnyTimes() storageMock.EXPECT().HeadStorage().AnyTimes().Return(headStorage) storageMock.EXPECT().StateStorage().AnyTimes().Return(stateStorage) treeSyncerMock.EXPECT().Name().AnyTimes().Return(treesyncer.CName) @@ -108,6 +119,7 @@ func newHeadSyncFixture(t *testing.T) *headSyncFixture { a := &app.App{} a.Register(spaceState). Register(aclMock). + Register(kvMock). Register(mockConfig{}). Register(configurationMock). Register(storageMock). @@ -121,6 +133,8 @@ func newHeadSyncFixture(t *testing.T) *headSyncFixture { spaceState: spaceState, ctrl: ctrl, app: a, + kvMock: kvMock, + defStoreMock: defStore, configurationMock: configurationMock, storageMock: storageMock, diffContainerMock: diffContainerMock, @@ -164,14 +178,16 @@ func TestHeadSync(t *testing.T) { headEntries := []headstorage.HeadsEntry{ { - Id: "id1", - Heads: []string{"h1", "h2"}, - IsDerived: false, + Id: "id1", + Heads: []string{"h1", "h2"}, + CommonSnapshot: "id1", + IsDerived: false, }, { - Id: "id2", - Heads: []string{"h3", "h4"}, - IsDerived: false, + Id: "id2", + Heads: []string{"h3", "h4"}, + CommonSnapshot: "id2", + IsDerived: false, }, } fx.headStorage.EXPECT().IterateEntries(gomock.Any(), gomock.Any(), gomock.Any()). @@ -196,8 +212,9 @@ func TestHeadSync(t *testing.T) { Id: "aclId", Head: "headId", }) - fx.diffContainerMock.EXPECT().NewDiff().Return(fx.diffMock) - fx.diffContainerMock.EXPECT().OldDiff().Return(fx.diffMock) + fx.diffMock.EXPECT().Set([]ldiff.Element{}) + fx.diffContainerMock.EXPECT().NewDiff().AnyTimes().Return(fx.diffMock) + fx.diffContainerMock.EXPECT().OldDiff().AnyTimes().Return(fx.diffMock) fx.diffMock.EXPECT().Hash().AnyTimes().Return("hash") fx.stateStorage.EXPECT().SetHash(gomock.Any(), "hash", "hash").Return(nil) fx.diffSyncerMock.EXPECT().Sync(gomock.Any()).Return(nil) @@ -215,14 +232,16 @@ func TestHeadSync(t *testing.T) { headEntries := []headstorage.HeadsEntry{ { - Id: "id1", - Heads: []string{"id1"}, - IsDerived: true, + Id: "id1", + Heads: []string{"id1"}, + CommonSnapshot: "id1", + IsDerived: true, }, { - Id: "id2", - Heads: []string{"h3", "h4"}, - IsDerived: false, + Id: "id2", + Heads: []string{"h3", "h4"}, + CommonSnapshot: "id2", + IsDerived: false, }, } fx.headStorage.EXPECT().IterateEntries(gomock.Any(), gomock.Any(), gomock.Any()). @@ -244,8 +263,9 @@ func TestHeadSync(t *testing.T) { Id: "aclId", Head: "headId", }) - fx.diffContainerMock.EXPECT().NewDiff().Return(fx.diffMock) - fx.diffContainerMock.EXPECT().OldDiff().Return(fx.diffMock) + fx.diffMock.EXPECT().Set([]ldiff.Element{}) + fx.diffContainerMock.EXPECT().NewDiff().AnyTimes().Return(fx.diffMock) + fx.diffContainerMock.EXPECT().OldDiff().AnyTimes().Return(fx.diffMock) fx.diffMock.EXPECT().Hash().AnyTimes().Return("hash") fx.stateStorage.EXPECT().SetHash(gomock.Any(), "hash", "hash").Return(nil) fx.diffSyncerMock.EXPECT().Sync(gomock.Any()).Return(nil) diff --git a/commonspace/headsync/statestorage/statestorage.go b/commonspace/headsync/statestorage/statestorage.go index 9d62376d..23eda96b 100644 --- a/commonspace/headsync/statestorage/statestorage.go +++ b/commonspace/headsync/statestorage/statestorage.go @@ -33,6 +33,7 @@ const ( idKey = "id" oldHashKey = "oh" newHashKey = "nh" + legacyHashKey = "h" headerKey = "e" aclIdKey = "a" settingsIdKey = "s" @@ -108,12 +109,8 @@ func Create(ctx context.Context, state State, store anystore.DB) (st StateStorag return nil, err } storage, err := CreateTx(tx.Context(), state, store) - defer func() { - if err != nil { - tx.Rollback() - } - }() if err != nil { + tx.Rollback() return nil, err } return storage, tx.Commit() @@ -149,12 +146,21 @@ func (s *stateStorage) SettingsId() string { } func (s *stateStorage) stateFromDoc(doc anystore.Doc) State { + var ( + oldHash = doc.Value().GetString(oldHashKey) + newHash = doc.Value().GetString(newHashKey) + ) + // legacy hash is used for backward compatibility, which was due to a mistake in key names + if oldHash == "" || newHash == "" { + oldHash = doc.Value().GetString(legacyHashKey) + newHash = oldHash + } return State{ SpaceId: doc.Value().GetString(idKey), SettingsId: doc.Value().GetString(settingsIdKey), AclId: doc.Value().GetString(aclIdKey), - OldHash: doc.Value().GetString(newHashKey), - NewHash: doc.Value().GetString(oldHashKey), + OldHash: oldHash, + NewHash: newHash, SpaceHeader: doc.Value().GetBytes(headerKey), } } diff --git a/commonspace/mock_commonspace/mock_commonspace.go b/commonspace/mock_commonspace/mock_commonspace.go index 49e2c9b2..b87cb729 100644 --- a/commonspace/mock_commonspace/mock_commonspace.go +++ b/commonspace/mock_commonspace/mock_commonspace.go @@ -18,6 +18,7 @@ import ( aclclient "github.com/anyproto/any-sync/commonspace/acl/aclclient" headsync "github.com/anyproto/any-sync/commonspace/headsync" syncacl "github.com/anyproto/any-sync/commonspace/object/acl/syncacl" + kvinterfaces "github.com/anyproto/any-sync/commonspace/object/keyvalue/kvinterfaces" treesyncer "github.com/anyproto/any-sync/commonspace/object/treesyncer" objecttreebuilder "github.com/anyproto/any-sync/commonspace/objecttreebuilder" spacestorage "github.com/anyproto/any-sync/commonspace/spacestorage" @@ -224,6 +225,20 @@ func (mr *MockSpaceMockRecorder) Init(ctx any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Init", reflect.TypeOf((*MockSpace)(nil).Init), ctx) } +// KeyValue mocks base method. +func (m *MockSpace) KeyValue() kvinterfaces.KeyValueService { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "KeyValue") + ret0, _ := ret[0].(kvinterfaces.KeyValueService) + return ret0 +} + +// KeyValue indicates an expected call of KeyValue. +func (mr *MockSpaceMockRecorder) KeyValue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "KeyValue", reflect.TypeOf((*MockSpace)(nil).KeyValue)) +} + // Storage mocks base method. func (m *MockSpace) Storage() spacestorage.SpaceStorage { m.ctrl.T.Helper() diff --git a/commonspace/object/acl/list/aclstate.go b/commonspace/object/acl/list/aclstate.go index f326991a..97030644 100644 --- a/commonspace/object/acl/list/aclstate.go +++ b/commonspace/object/acl/list/aclstate.go @@ -130,6 +130,20 @@ func (st *AclState) CurrentReadKeyId() string { return st.readKeyChanges[len(st.readKeyChanges)-1] } +func (st *AclState) ReadKeyForAclId(id string) (string, error) { + recIdx, ok := st.list.indexes[id] + if !ok { + return "", ErrNoSuchRecord + } + for i := len(st.readKeyChanges) - 1; i >= 0; i-- { + recId := st.readKeyChanges[i] + if recIdx >= st.list.indexes[recId] { + return recId, nil + } + } + return "", ErrNoSuchRecord +} + func (st *AclState) AccountKey() crypto.PrivKey { return st.key } @@ -150,6 +164,13 @@ func (st *AclState) CurrentMetadataKey() (crypto.PubKey, error) { return curKeys.MetadataPubKey, nil } +func (st *AclState) FirstMetadataKey() (crypto.PrivKey, error) { + if firstKey, ok := st.keys[st.id]; ok && firstKey.MetadataPrivKey != nil { + return firstKey.MetadataPrivKey, nil + } + return nil, ErrNoMetadataKey +} + func (st *AclState) Keys() map[string]AclKeys { return st.keys } diff --git a/commonspace/object/acl/list/aclstate_test.go b/commonspace/object/acl/list/aclstate_test.go index cae40dc8..2cc178f8 100644 --- a/commonspace/object/acl/list/aclstate_test.go +++ b/commonspace/object/acl/list/aclstate_test.go @@ -1,8 +1,11 @@ package list import ( + "crypto/rand" "testing" + "github.com/anyproto/any-sync/util/crypto" + "github.com/stretchr/testify/require" ) @@ -68,3 +71,43 @@ func TestAclStateIsEmpty(t *testing.T) { require.True(t, st.IsEmpty()) }) } + +func TestAclState_FirstMetadataKey(t *testing.T) { + t.Run("returns first metadata key successfully", func(t *testing.T) { + privKey, _, err := crypto.GenerateEd25519Key(rand.Reader) + require.NoError(t, err) + pubKey := privKey.GetPublic() + readKey := crypto.NewAES() + state := &AclState{ + id: "recordId", + keys: map[string]AclKeys{ + "recordId": { + ReadKey: readKey, + MetadataPrivKey: privKey, + MetadataPubKey: pubKey, + }, + }, + } + key, err := state.FirstMetadataKey() + require.NoError(t, err) + require.Equal(t, privKey, key) + }) + t.Run("first metadata is nil", func(t *testing.T) { + state := &AclState{ + id: "recordId", + keys: map[string]AclKeys{ + "recordId": { + ReadKey: crypto.NewAES(), + }, + }, + } + key, err := state.FirstMetadataKey() + require.ErrorIs(t, err, ErrNoMetadataKey) + require.Nil(t, key) + }) + t.Run("returns error when no read key changes", func(t *testing.T) { + state := &AclState{} + _, err := state.FirstMetadataKey() + require.ErrorIs(t, err, ErrNoMetadataKey) + }) +} diff --git a/commonspace/object/acl/list/storage.go b/commonspace/object/acl/list/storage.go index a54eedf3..9168bbe4 100644 --- a/commonspace/object/acl/list/storage.go +++ b/commonspace/object/acl/list/storage.go @@ -66,12 +66,8 @@ func CreateStorage(ctx context.Context, root *consensusproto.RawRecordWithId, he return nil, err } storage, err := CreateStorageTx(tx.Context(), root, headStorage, store) - defer func() { - if err != nil { - tx.Rollback() - } - }() if err != nil { + tx.Rollback() return nil, err } return storage, tx.Commit() @@ -210,6 +206,13 @@ func (s *storage) AddAll(ctx context.Context, records []StorageRecord) error { if err != nil { return fmt.Errorf("failed to create write tx: %w", err) } + defer func() { + if err != nil { + _ = tx.Rollback() + } else { + err = tx.Commit() + } + }() vals := make([]*anyenc.Value, 0, len(records)) for _, ch := range records { newVal := newStorageRecordValue(ch, arena) @@ -217,20 +220,14 @@ func (s *storage) AddAll(ctx context.Context, records []StorageRecord) error { } err = s.recordsColl.Insert(tx.Context(), vals...) if err != nil { - tx.Rollback() - return nil + return err } head := records[len(records)-1].Id update := headstorage.HeadsUpdate{ Id: s.id, Heads: []string{head}, } - err = s.headStorage.UpdateEntryTx(tx.Context(), update) - if err != nil { - tx.Rollback() - return err - } - return tx.Commit() + return s.headStorage.UpdateEntryTx(tx.Context(), update) } func (s *storage) Id() string { diff --git a/commonspace/object/acl/syncacl/headupdate.go b/commonspace/object/acl/syncacl/headupdate.go index a58cd546..30b09e0a 100644 --- a/commonspace/object/acl/syncacl/headupdate.go +++ b/commonspace/object/acl/syncacl/headupdate.go @@ -1,6 +1,7 @@ package syncacl import ( + "github.com/anyproto/any-sync/commonspace/spacesyncproto" "github.com/anyproto/any-sync/commonspace/sync/objectsync/objectmessages" "github.com/anyproto/any-sync/consensus/consensusproto" ) @@ -24,6 +25,10 @@ func (h *InnerHeadUpdate) MsgSize() uint64 { return size + uint64(len(h.head)) + uint64(len(h.root.Id)) + uint64(len(h.root.Payload)) } +func (h *InnerHeadUpdate) ObjectType() spacesyncproto.ObjectType { + return spacesyncproto.ObjectType_Acl +} + func (h *InnerHeadUpdate) Prepare() error { logMsg := consensusproto.WrapHeadUpdate(&consensusproto.LogHeadUpdate{ Head: h.head, diff --git a/commonspace/object/keyvalue/keyvalue.go b/commonspace/object/keyvalue/keyvalue.go new file mode 100644 index 00000000..118f230f --- /dev/null +++ b/commonspace/object/keyvalue/keyvalue.go @@ -0,0 +1,245 @@ +package keyvalue + +import ( + "context" + "errors" + + "go.uber.org/zap" + "storj.io/drpc" + + "github.com/anyproto/any-sync/accountservice" + "github.com/anyproto/any-sync/app" + "github.com/anyproto/any-sync/app/logger" + "github.com/anyproto/any-sync/commonspace/object/acl/list" + "github.com/anyproto/any-sync/commonspace/object/acl/syncacl" + "github.com/anyproto/any-sync/commonspace/object/keyvalue/keyvaluestorage" + "github.com/anyproto/any-sync/commonspace/object/keyvalue/keyvaluestorage/syncstorage" + "github.com/anyproto/any-sync/commonspace/object/keyvalue/kvinterfaces" + "github.com/anyproto/any-sync/commonspace/spacestate" + "github.com/anyproto/any-sync/commonspace/spacestorage" + "github.com/anyproto/any-sync/commonspace/spacesyncproto" + "github.com/anyproto/any-sync/commonspace/sync" + "github.com/anyproto/any-sync/commonspace/sync/objectsync/objectmessages" + "github.com/anyproto/any-sync/net/peer" + "github.com/anyproto/any-sync/net/rpc/rpcerr" + "github.com/anyproto/any-sync/util/cidutil" +) + +var ErrUnexpectedMessageType = errors.New("unexpected message type") + +var log = logger.NewNamed(kvinterfaces.CName) + +type keyValueService struct { + storageId string + spaceId string + ctx context.Context + cancel context.CancelFunc + + limiter *concurrentLimiter + defaultStore keyvaluestorage.Storage + clientFactory spacesyncproto.ClientFactory +} + +func New() kvinterfaces.KeyValueService { + return &keyValueService{} +} + +func (k *keyValueService) DefaultStore() keyvaluestorage.Storage { + return k.defaultStore +} + +func (k *keyValueService) SyncWithPeer(p peer.Peer) (err error) { + k.limiter.ScheduleRequest(k.ctx, p.Id(), func() { + err = k.syncWithPeer(k.ctx, p) + if err != nil { + log.Error("failed to sync with peer", zap.String("peerId", p.Id()), zap.Error(err)) + } + }) + return nil +} + +func (k *keyValueService) syncWithPeer(ctx context.Context, p peer.Peer) (err error) { + conn, err := p.AcquireDrpcConn(ctx) + if err != nil { + return + } + defer p.ReleaseDrpcConn(conn) + var ( + client = k.clientFactory.Client(conn) + rdiff = NewRemoteDiff(k.spaceId, client) + diff = k.defaultStore.InnerStorage().Diff() + ) + newIds, changedIds, theirChangedIds, removedIds, err := diff.CompareDiff(ctx, rdiff) + err = rpcerr.Unwrap(err) + if err != nil { + return err + } + innerStorage := k.defaultStore.InnerStorage() + stream, err := client.StoreElements(ctx) + if err != nil { + return err + } + defer stream.CloseSend() + err = stream.Send(&spacesyncproto.StoreKeyValue{SpaceId: k.spaceId}) + if err != nil { + return err + } + for _, id := range append(removedIds, changedIds...) { + kv, err := innerStorage.GetKeyPeerId(ctx, id) + if err != nil { + return err + } + err = stream.Send(kv.Proto()) + if err != nil { + return err + } + } + for _, id := range append(theirChangedIds, newIds...) { + kv := &spacesyncproto.StoreKeyValue{ + KeyPeerId: id, + } + err := stream.Send(kv) + if err != nil { + return err + } + } + err = stream.Send(&spacesyncproto.StoreKeyValue{}) + if err != nil { + return err + } + var messages []*spacesyncproto.StoreKeyValue + for { + msg, err := stream.Recv() + if err != nil { + return err + } + if msg.KeyPeerId == "" { + break + } + messages = append(messages, msg) + } + return k.defaultStore.SetRaw(ctx, messages...) +} + +func (k *keyValueService) HandleStoreDiffRequest(ctx context.Context, req *spacesyncproto.StoreDiffRequest) (resp *spacesyncproto.StoreDiffResponse, err error) { + return HandleRangeRequest(ctx, k.defaultStore.InnerStorage().Diff(), req) +} + +func (k *keyValueService) HandleStoreElementsRequest(ctx context.Context, stream spacesyncproto.DRPCSpaceSync_StoreElementsStream) (err error) { + var ( + messagesToSave []*spacesyncproto.StoreKeyValue + messagesToSend []string + ) + for { + msg, err := stream.Recv() + if err != nil { + return err + } + if msg.KeyPeerId == "" { + break + } + if msg.Value != nil { + messagesToSave = append(messagesToSave, msg) + } else { + messagesToSend = append(messagesToSend, msg.KeyPeerId) + } + } + innerStorage := k.defaultStore.InnerStorage() + isError := false + for _, msg := range messagesToSend { + kv, err := innerStorage.GetKeyPeerId(ctx, msg) + if err != nil { + log.Warn("failed to get key value", zap.String("key", msg), zap.Error(err)) + continue + } + err = stream.Send(kv.Proto()) + if err != nil { + log.Warn("failed to send key value", zap.String("key", msg), zap.Error(err)) + isError = true + break + } + } + if !isError { + err = stream.Send(&spacesyncproto.StoreKeyValue{}) + if err != nil { + return err + } + } + return k.defaultStore.SetRaw(ctx, messagesToSave...) +} + +func (k *keyValueService) HandleMessage(ctx context.Context, headUpdate drpc.Message) (err error) { + update, ok := headUpdate.(*objectmessages.HeadUpdate) + if !ok { + return ErrUnexpectedMessageType + } + keyValueMsg := &spacesyncproto.StoreKeyValues{} + err = keyValueMsg.UnmarshalVT(update.Bytes) + if err != nil { + objectmessages.FreeHeadUpdate(update) + return err + } + objectmessages.FreeHeadUpdate(update) + return k.defaultStore.SetRaw(ctx, keyValueMsg.KeyValues...) +} + +func (k *keyValueService) Init(a *app.App) (err error) { + k.ctx, k.cancel = context.WithCancel(context.Background()) + spaceState := a.MustComponent(spacestate.CName).(*spacestate.SpaceState) + k.spaceId = spaceState.SpaceId + k.clientFactory = spacesyncproto.ClientFactoryFunc(spacesyncproto.NewDRPCSpaceSyncClient) + k.limiter = newConcurrentLimiter() + accountService := a.MustComponent(accountservice.CName).(accountservice.Service) + aclList := a.MustComponent(syncacl.CName).(list.AclList) + spaceStorage := a.MustComponent(spacestorage.CName).(spacestorage.SpaceStorage) + syncService := a.MustComponent(sync.CName).(sync.SyncService) + k.storageId, err = storageIdFromSpace(k.spaceId) + if err != nil { + return err + } + indexer := a.Component(keyvaluestorage.IndexerCName).(keyvaluestorage.Indexer) + if indexer == nil { + indexer = keyvaluestorage.NoOpIndexer{} + } + syncClient := syncstorage.New(spaceState.SpaceId, syncService) + k.defaultStore, err = keyvaluestorage.New( + k.ctx, + k.storageId, + spaceStorage.AnyStore(), + spaceStorage.HeadStorage(), + accountService.Account(), + syncClient, + aclList, + indexer) + return +} + +func (k *keyValueService) Name() (name string) { + return kvinterfaces.CName +} + +func (k *keyValueService) Run(ctx context.Context) (err error) { + return k.defaultStore.Prepare() +} + +func (k *keyValueService) Close(ctx context.Context) (err error) { + k.cancel() + k.limiter.Close() + return nil +} + +func storageIdFromSpace(spaceId string) (storageId string, err error) { + header := &spacesyncproto.StorageHeader{ + SpaceId: spaceId, + StorageName: "default", + } + data, err := header.MarshalVT() + if err != nil { + return "", err + } + cid, err := cidutil.NewCidFromBytes(data) + if err != nil { + return "", err + } + return cid, nil +} diff --git a/commonspace/object/keyvalue/keyvalue_test.go b/commonspace/object/keyvalue/keyvalue_test.go new file mode 100644 index 00000000..301d9d0d --- /dev/null +++ b/commonspace/object/keyvalue/keyvalue_test.go @@ -0,0 +1,371 @@ +package keyvalue + +import ( + "bytes" + "context" + "fmt" + "math/rand" + "path/filepath" + "sort" + "strconv" + "strings" + "testing" + "time" + + anystore "github.com/anyproto/any-store" + "github.com/stretchr/testify/require" + + "github.com/anyproto/any-sync/commonspace/object/accountdata" + "github.com/anyproto/any-sync/commonspace/object/acl/list" + "github.com/anyproto/any-sync/commonspace/object/keyvalue/keyvaluestorage" + "github.com/anyproto/any-sync/commonspace/object/keyvalue/keyvaluestorage/innerstorage" + "github.com/anyproto/any-sync/commonspace/spacepayloads" + "github.com/anyproto/any-sync/commonspace/spacestorage" + "github.com/anyproto/any-sync/commonspace/spacesyncproto" + "github.com/anyproto/any-sync/net/peer" + "github.com/anyproto/any-sync/net/rpc/rpctest" + "github.com/anyproto/any-sync/util/crypto" +) + +func TestKeyValueService(t *testing.T) { + t.Run("different keys", func(t *testing.T) { + fxClient, fxServer, serverPeer := prepareFixtures(t) + fxClient.add(t, "key1", []byte("value1")) + fxClient.add(t, "key2", []byte("value2")) + fxServer.add(t, "key3", []byte("value3")) + fxServer.add(t, "key4", []byte("value4")) + err := fxClient.SyncWithPeer(serverPeer) + require.NoError(t, err) + fxClient.limiter.Close() + fxClient.check(t, "key3", []byte("value3")) + fxClient.check(t, "key4", []byte("value4")) + fxServer.check(t, "key1", []byte("value1")) + fxServer.check(t, "key2", []byte("value2")) + }) + + t.Run("change same keys, different values", func(t *testing.T) { + fxClient, fxServer, serverPeer := prepareFixtures(t) + fxClient.add(t, "key1", []byte("value1")) + fxServer.add(t, "key1", []byte("value2")) + err := fxClient.SyncWithPeer(serverPeer) + require.NoError(t, err) + fxClient.limiter.Close() + fxClient.check(t, "key1", []byte("value1")) + fxClient.check(t, "key1", []byte("value2")) + fxServer.check(t, "key1", []byte("value1")) + fxServer.check(t, "key1", []byte("value2")) + fxClient.add(t, "key1", []byte("value1-2")) + fxServer.add(t, "key1", []byte("value2-2")) + err = fxClient.SyncWithPeer(serverPeer) + require.NoError(t, err) + fxClient.limiter.Close() + fxClient.check(t, "key1", []byte("value1-2")) + fxClient.check(t, "key1", []byte("value2-2")) + fxServer.check(t, "key1", []byte("value1-2")) + fxServer.check(t, "key1", []byte("value2-2")) + }) + + t.Run("random keys and values", func(t *testing.T) { + rand.Seed(time.Now().UnixNano()) + diffEntries := 100 + ovelappingEntries := 10 + fxClient, fxServer, serverPeer := prepareFixtures(t) + numClientEntries := 5 + rand.Intn(diffEntries) + numServerEntries := 5 + rand.Intn(diffEntries) + allKeys := make(map[string]bool) + for i := 0; i < numClientEntries; i++ { + key := fmt.Sprintf("client-key-%d", i) + value := []byte(fmt.Sprintf("client-value-%d", i)) + fxClient.add(t, key, value) + allKeys[key] = true + } + for i := 0; i < numServerEntries; i++ { + key := fmt.Sprintf("server-key-%d", i) + value := []byte(fmt.Sprintf("server-value-%d", i)) + fxServer.add(t, key, value) + allKeys[key] = true + } + numOverlappingKeys := 3 + rand.Intn(ovelappingEntries) + for i := 0; i < numOverlappingKeys; i++ { + key := fmt.Sprintf("overlap-key-%d", i) + clientValue := []byte(fmt.Sprintf("client-overlap-value-%d", i)) + serverValue := []byte(fmt.Sprintf("server-overlap-value-%d", i)) + fxClient.add(t, key, clientValue) + fxServer.add(t, key, serverValue) + allKeys[key] = true + } + err := fxClient.SyncWithPeer(serverPeer) + require.NoError(t, err) + fxClient.limiter.Close() + + for key := range allKeys { + if strings.HasPrefix(key, "client-key-") { + i, _ := strconv.Atoi(strings.TrimPrefix(key, "client-key-")) + value := []byte(fmt.Sprintf("client-value-%d", i)) + fxClient.check(t, key, value) + fxServer.check(t, key, value) + } + if strings.HasPrefix(key, "server-key-") { + i, _ := strconv.Atoi(strings.TrimPrefix(key, "server-key-")) + value := []byte(fmt.Sprintf("server-value-%d", i)) + fxClient.check(t, key, value) + fxServer.check(t, key, value) + } + } + for i := 0; i < numOverlappingKeys; i++ { + key := fmt.Sprintf("overlap-key-%d", i) + clientValue := []byte(fmt.Sprintf("client-overlap-value-%d", i)) + serverValue := []byte(fmt.Sprintf("server-overlap-value-%d", i)) + + fxClient.check(t, key, clientValue) + fxClient.check(t, key, serverValue) + fxServer.check(t, key, clientValue) + fxServer.check(t, key, serverValue) + } + foundClientKeys := make(map[string]bool) + foundServerKeys := make(map[string]bool) + err = fxClient.defaultStore.Iterate(context.Background(), func(decryptor keyvaluestorage.Decryptor, key string, values []innerstorage.KeyValue) (bool, error) { + foundClientKeys[key] = true + return true, nil + }) + require.NoError(t, err) + err = fxServer.defaultStore.Iterate(context.Background(), func(decryptor keyvaluestorage.Decryptor, key string, values []innerstorage.KeyValue) (bool, error) { + foundServerKeys[key] = true + return true, nil + }) + require.NoError(t, err) + require.True(t, mapEqual(allKeys, foundServerKeys), "expected all client keys to be found") + require.True(t, mapEqual(foundClientKeys, foundServerKeys), "expected all client keys to be found") + }) +} + +func TestKeyValueServiceIterate(t *testing.T) { + t.Run("empty storage", func(t *testing.T) { + fxClient, _, _ := prepareFixtures(t) + var keys []string + err := fxClient.defaultStore.Iterate(context.Background(), func(decryptor keyvaluestorage.Decryptor, key string, values []innerstorage.KeyValue) (bool, error) { + keys = append(keys, key) + return true, nil + }) + require.NoError(t, err) + require.Empty(t, keys, "expected no keys in empty storage") + }) + + t.Run("single key later value", func(t *testing.T) { + fxClient, _, _ := prepareFixtures(t) + err := fxClient.defaultStore.Set(context.Background(), "test-key", []byte("value1")) + require.NoError(t, err) + err = fxClient.defaultStore.Set(context.Background(), "test-key", []byte("value2")) + require.NoError(t, err) + var keys []string + valueCount := 0 + err = fxClient.defaultStore.Iterate(context.Background(), func(decryptor keyvaluestorage.Decryptor, key string, values []innerstorage.KeyValue) (bool, error) { + keys = append(keys, key) + valueCount = len(values) + + for _, kv := range values { + val, err := decryptor(kv) + require.NoError(t, err) + require.Equal(t, "value2", string(val)) + } + return true, nil + }) + require.NoError(t, err) + require.Equal(t, 1, len(keys), "expected one key") + require.Equal(t, "test-key", keys[0], "expected key to be 'test-key'") + require.Equal(t, 1, valueCount, "expected one value for key") + }) + + t.Run("multiple keys", func(t *testing.T) { + fxClient, _, _ := prepareFixtures(t) + testKeys := []string{"key1", "key2", "key3"} + for _, key := range testKeys { + err := fxClient.defaultStore.Set(context.Background(), key, []byte("value-"+key)) + require.NoError(t, err) + } + var foundKeys []string + err := fxClient.defaultStore.Iterate(context.Background(), func(decryptor keyvaluestorage.Decryptor, key string, values []innerstorage.KeyValue) (bool, error) { + foundKeys = append(foundKeys, key) + require.Equal(t, 1, len(values), "Expected one value for key: "+key) + val, err := decryptor(values[0]) + require.NoError(t, err) + require.Equal(t, "value-"+key, string(val), "Value doesn't match for key: "+key) + + return true, nil + }) + require.NoError(t, err) + sort.Strings(foundKeys) + sort.Strings(testKeys) + require.Equal(t, testKeys, foundKeys, "Expected all keys to be found") + }) + + t.Run("early termination", func(t *testing.T) { + fxClient, _, _ := prepareFixtures(t) + testKeys := []string{"key1", "key2", "key3", "key4", "key5"} + for _, key := range testKeys { + err := fxClient.defaultStore.Set(context.Background(), key, []byte("value-"+key)) + require.NoError(t, err) + } + + var foundKeys []string + err := fxClient.defaultStore.Iterate(context.Background(), func(decryptor keyvaluestorage.Decryptor, key string, values []innerstorage.KeyValue) (bool, error) { + foundKeys = append(foundKeys, key) + return len(foundKeys) < 2, nil + }) + require.NoError(t, err) + require.Equal(t, 2, len(foundKeys), "expected to find exactly 2 keys before stopping") + }) + + t.Run("error during iteration", func(t *testing.T) { + fxClient, _, _ := prepareFixtures(t) + + err := fxClient.defaultStore.Set(context.Background(), "test-key", []byte("test-value")) + require.NoError(t, err) + + expectedErr := context.Canceled + err = fxClient.defaultStore.Iterate(context.Background(), func(decryptor keyvaluestorage.Decryptor, key string, values []innerstorage.KeyValue) (bool, error) { + return false, expectedErr + }) + require.Equal(t, expectedErr, err, "expected error to be propagated") + }) +} + +func prepareFixtures(t *testing.T) (fxClient *fixture, fxServer *fixture, serverPeer peer.Peer) { + firstKeys, err := accountdata.NewRandom() + require.NoError(t, err) + secondKeys, err := accountdata.NewRandom() + require.NoError(t, err) + secondKeys.SignKey = firstKeys.SignKey + payload := newStorageCreatePayload(t, firstKeys) + fxClient = newFixture(t, firstKeys, payload) + fxServer = newFixture(t, secondKeys, payload) + serverConn, clientConn := rpctest.MultiConnPair(firstKeys.PeerId, secondKeys.PeerId) + serverPeer, err = peer.NewPeer(serverConn, fxClient.server) + require.NoError(t, err) + _, err = peer.NewPeer(clientConn, fxServer.server) + require.NoError(t, err) + return +} + +func mapEqual[K comparable, V comparable](map1, map2 map[K]V) bool { + if len(map1) != len(map2) { + return false + } + for key, val1 := range map1 { + if val2, ok := map2[key]; !ok || val1 != val2 { + return false + } + } + return true +} + +var ctx = context.Background() + +type noOpSyncClient struct{} + +func (n noOpSyncClient) Broadcast(ctx context.Context, objectId string, keyValues ...innerstorage.KeyValue) error { + return nil +} + +type fixture struct { + *keyValueService + server *rpctest.TestServer +} + +func newFixture(t *testing.T, keys *accountdata.AccountKeys, spacePayload spacestorage.SpaceStorageCreatePayload) *fixture { + storePath := filepath.Join(t.TempDir(), "store.db") + anyStore, err := anystore.Open(ctx, storePath, nil) + require.NoError(t, err) + storage, err := spacestorage.Create(ctx, anyStore, spacePayload) + require.NoError(t, err) + aclStorage, err := storage.AclStorage() + require.NoError(t, err) + aclList, err := list.BuildAclListWithIdentity(keys, aclStorage, list.NoOpAcceptorVerifier{}) + require.NoError(t, err) + storageId := "kv.storage" + rpcHandler := rpctest.NewTestServer() + defaultStorage, err := keyvaluestorage.New(ctx, + storageId, + anyStore, + storage.HeadStorage(), + keys, + noOpSyncClient{}, + aclList, + keyvaluestorage.NoOpIndexer{}) + require.NoError(t, err) + ctx, cancel := context.WithCancel(ctx) + service := &keyValueService{ + spaceId: storage.Id(), + storageId: storageId, + limiter: newConcurrentLimiter(), + ctx: ctx, + cancel: cancel, + clientFactory: spacesyncproto.ClientFactoryFunc(spacesyncproto.NewDRPCSpaceSyncClient), + defaultStore: defaultStorage, + } + require.NoError(t, spacesyncproto.DRPCRegisterSpaceSync(rpcHandler, &testServer{service: service, t: t})) + return &fixture{ + keyValueService: service, + server: rpcHandler, + } +} + +func (fx *fixture) add(t *testing.T, key string, value []byte) { + err := fx.defaultStore.Set(ctx, key, value) + require.NoError(t, err) +} + +func (fx *fixture) check(t *testing.T, key string, value []byte) (isFound bool) { + err := fx.defaultStore.GetAll(ctx, key, func(decryptor keyvaluestorage.Decryptor, values []innerstorage.KeyValue) error { + for _, v := range values { + decryptedValue, err := decryptor(v) + require.NoError(t, err) + if bytes.Equal(value, decryptedValue) { + isFound = true + break + } + } + return nil + }) + require.NoError(t, err) + return +} + +func newStorageCreatePayload(t *testing.T, keys *accountdata.AccountKeys) spacestorage.SpaceStorageCreatePayload { + masterKey, _, err := crypto.GenerateRandomEd25519KeyPair() + require.NoError(t, err) + metaKey, _, err := crypto.GenerateRandomEd25519KeyPair() + require.NoError(t, err) + readKey := crypto.NewAES() + meta := []byte("account") + payload := spacepayloads.SpaceCreatePayload{ + SigningKey: keys.SignKey, + SpaceType: "space", + ReplicationKey: 10, + SpacePayload: nil, + MasterKey: masterKey, + ReadKey: readKey, + MetadataKey: metaKey, + Metadata: meta, + } + createSpace, err := spacepayloads.StoragePayloadForSpaceCreate(payload) + require.NoError(t, err) + return createSpace +} + +type testServer struct { + spacesyncproto.DRPCSpaceSyncUnimplementedServer + service *keyValueService + t *testing.T +} + +func (t *testServer) StoreDiff(ctx context.Context, req *spacesyncproto.StoreDiffRequest) (*spacesyncproto.StoreDiffResponse, error) { + return t.service.HandleStoreDiffRequest(ctx, req) +} + +func (t *testServer) StoreElements(stream spacesyncproto.DRPCSpaceSync_StoreElementsStream) error { + msg, err := stream.Recv() + require.NoError(t.t, err) + require.NotEmpty(t.t, msg.SpaceId) + return t.service.HandleStoreElementsRequest(ctx, stream) +} diff --git a/commonspace/object/keyvalue/keyvaluestorage/innerstorage/element.go b/commonspace/object/keyvalue/keyvaluestorage/innerstorage/element.go new file mode 100644 index 00000000..c4842d8f --- /dev/null +++ b/commonspace/object/keyvalue/keyvaluestorage/innerstorage/element.go @@ -0,0 +1,92 @@ +package innerstorage + +import ( + "errors" + + "github.com/anyproto/any-store/anyenc" + + "github.com/anyproto/any-sync/commonspace/spacesyncproto" + "github.com/anyproto/any-sync/util/crypto" +) + +var ErrInvalidSignature = errors.New("invalid signature") + +type KeyValue struct { + KeyPeerId string + ReadKeyId string + Key string + Value Value + TimestampMilli int + Identity string + PeerId string + AclId string +} + +type Value struct { + Value []byte + PeerSignature []byte + IdentitySignature []byte +} + +func KeyValueFromProto(proto *spacesyncproto.StoreKeyValue, verify bool) (kv KeyValue, err error) { + kv.KeyPeerId = proto.KeyPeerId + kv.Value.Value = proto.Value + kv.Value.PeerSignature = proto.PeerSignature + kv.Value.IdentitySignature = proto.IdentitySignature + innerValue := &spacesyncproto.StoreKeyInner{} + if err = innerValue.UnmarshalVT(proto.Value); err != nil { + return kv, err + } + kv.TimestampMilli = int(innerValue.TimestampMicro) + identity, err := crypto.UnmarshalEd25519PublicKeyProto(innerValue.Identity) + if err != nil { + return kv, err + } + peerId, err := crypto.UnmarshalEd25519PublicKeyProto(innerValue.Peer) + if err != nil { + return kv, err + } + kv.Identity = identity.Account() + kv.PeerId = peerId.PeerId() + kv.Key = innerValue.Key + kv.AclId = innerValue.AclHeadId + // TODO: check that key-peerId is equal to key+peerId? + if verify { + if verify, _ = identity.Verify(proto.Value, proto.IdentitySignature); !verify { + return kv, ErrInvalidSignature + } + if verify, _ = peerId.Verify(proto.Value, proto.PeerSignature); !verify { + return kv, ErrInvalidSignature + } + } + return kv, nil +} + +func (v Value) AnyEnc(a *anyenc.Arena) *anyenc.Value { + obj := a.NewObject() + obj.Set("v", a.NewBinary(v.Value)) + obj.Set("p", a.NewBinary(v.PeerSignature)) + obj.Set("i", a.NewBinary(v.IdentitySignature)) + return obj +} + +func (kv KeyValue) AnyEnc(a *anyenc.Arena) *anyenc.Value { + obj := a.NewObject() + obj.Set("id", a.NewString(kv.KeyPeerId)) + obj.Set("k", a.NewString(kv.Key)) + obj.Set("r", a.NewString(kv.ReadKeyId)) + obj.Set("v", kv.Value.AnyEnc(a)) + obj.Set("t", a.NewNumberInt(kv.TimestampMilli)) + obj.Set("i", a.NewString(kv.Identity)) + obj.Set("p", a.NewString(kv.PeerId)) + return obj +} + +func (kv KeyValue) Proto() *spacesyncproto.StoreKeyValue { + return &spacesyncproto.StoreKeyValue{ + KeyPeerId: kv.KeyPeerId, + Value: kv.Value.Value, + PeerSignature: kv.Value.PeerSignature, + IdentitySignature: kv.Value.IdentitySignature, + } +} diff --git a/commonspace/object/keyvalue/keyvaluestorage/innerstorage/keyvaluestorage.go b/commonspace/object/keyvalue/keyvaluestorage/innerstorage/keyvaluestorage.go new file mode 100644 index 00000000..5dcd6990 --- /dev/null +++ b/commonspace/object/keyvalue/keyvaluestorage/innerstorage/keyvaluestorage.go @@ -0,0 +1,249 @@ +package innerstorage + +import ( + "context" + "encoding/binary" + "errors" + "strings" + + anystore "github.com/anyproto/any-store" + "github.com/anyproto/any-store/anyenc" + "github.com/anyproto/any-store/query" + + "github.com/anyproto/any-sync/app/ldiff" + "github.com/anyproto/any-sync/commonspace/headsync/headstorage" +) + +var ( + parserPool = &anyenc.ParserPool{} + arenaPool = &anyenc.ArenaPool{} +) + +type KeyValueStorage interface { + Set(ctx context.Context, keyValues ...KeyValue) (err error) + Diff() ldiff.CompareDiff + GetKeyPeerId(ctx context.Context, keyPeerId string) (keyValue KeyValue, err error) + IterateValues(context.Context, func(kv KeyValue) (bool, error)) (err error) + IteratePrefix(context.Context, string, func(kv KeyValue) error) (err error) +} + +type storage struct { + diff ldiff.CompareDiff + headStorage headstorage.HeadStorage + collection anystore.Collection + store anystore.DB + storageName string +} + +func New(ctx context.Context, storageName string, headStorage headstorage.HeadStorage, store anystore.DB) (kv KeyValueStorage, err error) { + collection, err := store.Collection(ctx, storageName) + if err != nil { + return nil, err + } + tx, err := store.WriteTx(ctx) + if err != nil { + return nil, err + } + defer func() { + if err != nil { + _ = tx.Rollback() + } else { + err = tx.Commit() + } + }() + storage := &storage{ + storageName: storageName, + headStorage: headStorage, + collection: collection, + store: store, + diff: ldiff.New(32, 256).(ldiff.CompareDiff), + } + iter, err := storage.collection.Find(nil).Iter(ctx) + if err != nil { + return + } + defer func() { + _ = iter.Close() + }() + var ( + doc anystore.Doc + elements []ldiff.Element + ) + for iter.Next() { + if doc, err = iter.Doc(); err != nil { + return + } + elements = append(elements, anyEncToElement(doc.Value())) + } + storage.diff.Set(elements...) + hash := storage.diff.Hash() + err = headStorage.UpdateEntryTx(tx.Context(), headstorage.HeadsUpdate{ + Id: storageName, + Heads: []string{hash}, + }) + return storage, err +} + +func (s *storage) Diff() ldiff.CompareDiff { + return s.diff +} + +func (s *storage) GetKeyPeerId(ctx context.Context, keyPeerId string) (value KeyValue, err error) { + doc, err := s.collection.FindId(ctx, keyPeerId) + if err != nil { + return + } + return s.keyValueFromDoc(doc), nil +} + +func (s *storage) IterateValues(ctx context.Context, iterFunc func(kv KeyValue) (bool, error)) (err error) { + iter, err := s.collection.Find(nil).Iter(ctx) + if err != nil { + return + } + defer func() { + _ = iter.Close() + }() + var doc anystore.Doc + for iter.Next() { + if doc, err = iter.Doc(); err != nil { + return + } + continueIteration, err := iterFunc(s.keyValueFromDoc(doc)) + if err != nil { + return err + } + if !continueIteration { + break + } + } + return nil +} + +func (s *storage) IteratePrefix(ctx context.Context, prefix string, iterFunc func(kv KeyValue) error) (err error) { + filter := query.Key{Path: []string{"id"}, Filter: query.NewComp(query.CompOpGte, prefix)} + qry := s.collection.Find(filter).Sort("id") + iter, err := qry.Iter(ctx) + if err != nil { + return + } + defer func() { + _ = iter.Close() + }() + var doc anystore.Doc + for iter.Next() { + if doc, err = iter.Doc(); err != nil { + return + } + if !strings.Contains(doc.Value().GetString("id"), prefix) { + break + } + err := iterFunc(s.keyValueFromDoc(doc)) + if err != nil { + return err + } + } + return nil +} + +func (s *storage) keyValueFromDoc(doc anystore.Doc) KeyValue { + valueObj := doc.Value().GetObject("v") + value := Value{ + Value: valueObj.Get("v").GetBytes(), + PeerSignature: valueObj.Get("p").GetBytes(), + IdentitySignature: valueObj.Get("i").GetBytes(), + } + return KeyValue{ + KeyPeerId: doc.Value().GetString("id"), + ReadKeyId: doc.Value().GetString("r"), + Value: value, + TimestampMilli: doc.Value().GetInt("t"), + Identity: doc.Value().GetString("i"), + PeerId: doc.Value().GetString("p"), + Key: doc.Value().GetString("k"), + } +} + +func (s *storage) init(ctx context.Context) (err error) { + s.diff = ldiff.New(32, 256).(ldiff.CompareDiff) + iter, err := s.collection.Find(nil).Iter(ctx) + if err != nil { + return + } + defer func() { + _ = iter.Close() + }() + var doc anystore.Doc + var elements []ldiff.Element + for iter.Next() { + if doc, err = iter.Doc(); err != nil { + return + } + elements = append(elements, anyEncToElement(doc.Value())) + } + s.diff.Set(elements...) + return +} + +func (s *storage) Set(ctx context.Context, values ...KeyValue) (err error) { + tx, err := s.collection.WriteTx(ctx) + if err != nil { + return + } + defer func() { + if err != nil { + _ = tx.Rollback() + } else { + err = tx.Commit() + } + }() + ctx = tx.Context() + elements, err := s.updateValues(ctx, values...) + if err != nil { + return + } + s.diff.Set(elements...) + err = s.headStorage.UpdateEntryTx(ctx, headstorage.HeadsUpdate{ + Id: s.storageName, + Heads: []string{s.diff.Hash()}, + }) + return +} + +func (s *storage) updateValues(ctx context.Context, values ...KeyValue) (elements []ldiff.Element, err error) { + parser := parserPool.Get() + defer parserPool.Put(parser) + arena := arenaPool.Get() + defer arenaPool.Put(arena) + + elements = make([]ldiff.Element, 0, len(values)) + var doc anystore.Doc + for _, value := range values { + doc, err = s.collection.FindIdWithParser(ctx, parser, value.KeyPeerId) + isNotFound := errors.Is(err, anystore.ErrDocNotFound) + if err != nil && !isNotFound { + return + } + if !isNotFound { + if doc.Value().GetInt("t") >= value.TimestampMilli { + continue + } + } + arena.Reset() + val := value.AnyEnc(arena) + if err = s.collection.UpsertOne(ctx, val); err != nil { + return + } + elements = append(elements, anyEncToElement(val)) + } + return +} + +func anyEncToElement(val *anyenc.Value) ldiff.Element { + byteRepr := make([]byte, 8) + binary.BigEndian.PutUint64(byteRepr, uint64(val.GetInt("t"))) + return ldiff.Element{ + Id: val.GetString("id"), + Head: string(byteRepr), + } +} diff --git a/commonspace/object/keyvalue/keyvaluestorage/mock_keyvaluestorage/mock_keyvaluestorage.go b/commonspace/object/keyvalue/keyvaluestorage/mock_keyvaluestorage/mock_keyvaluestorage.go new file mode 100644 index 00000000..548d61f1 --- /dev/null +++ b/commonspace/object/keyvalue/keyvaluestorage/mock_keyvaluestorage/mock_keyvaluestorage.go @@ -0,0 +1,144 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/anyproto/any-sync/commonspace/object/keyvalue/keyvaluestorage (interfaces: Storage) +// +// Generated by this command: +// +// mockgen -destination mock_keyvaluestorage/mock_keyvaluestorage.go github.com/anyproto/any-sync/commonspace/object/keyvalue/keyvaluestorage Storage +// +// Package mock_keyvaluestorage is a generated GoMock package. +package mock_keyvaluestorage + +import ( + context "context" + reflect "reflect" + + innerstorage "github.com/anyproto/any-sync/commonspace/object/keyvalue/keyvaluestorage/innerstorage" + spacesyncproto "github.com/anyproto/any-sync/commonspace/spacesyncproto" + gomock "go.uber.org/mock/gomock" +) + +// MockStorage is a mock of Storage interface. +type MockStorage struct { + ctrl *gomock.Controller + recorder *MockStorageMockRecorder +} + +// MockStorageMockRecorder is the mock recorder for MockStorage. +type MockStorageMockRecorder struct { + mock *MockStorage +} + +// NewMockStorage creates a new mock instance. +func NewMockStorage(ctrl *gomock.Controller) *MockStorage { + mock := &MockStorage{ctrl: ctrl} + mock.recorder = &MockStorageMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockStorage) EXPECT() *MockStorageMockRecorder { + return m.recorder +} + +// GetAll mocks base method. +func (m *MockStorage) GetAll(arg0 context.Context, arg1 string, arg2 func(func(innerstorage.KeyValue) ([]byte, error), []innerstorage.KeyValue) error) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAll", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// GetAll indicates an expected call of GetAll. +func (mr *MockStorageMockRecorder) GetAll(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAll", reflect.TypeOf((*MockStorage)(nil).GetAll), arg0, arg1, arg2) +} + +// Id mocks base method. +func (m *MockStorage) Id() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Id") + ret0, _ := ret[0].(string) + return ret0 +} + +// Id indicates an expected call of Id. +func (mr *MockStorageMockRecorder) Id() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Id", reflect.TypeOf((*MockStorage)(nil).Id)) +} + +// InnerStorage mocks base method. +func (m *MockStorage) InnerStorage() innerstorage.KeyValueStorage { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InnerStorage") + ret0, _ := ret[0].(innerstorage.KeyValueStorage) + return ret0 +} + +// InnerStorage indicates an expected call of InnerStorage. +func (mr *MockStorageMockRecorder) InnerStorage() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InnerStorage", reflect.TypeOf((*MockStorage)(nil).InnerStorage)) +} + +// Iterate mocks base method. +func (m *MockStorage) Iterate(arg0 context.Context, arg1 func(func(innerstorage.KeyValue) ([]byte, error), string, []innerstorage.KeyValue) (bool, error)) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Iterate", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Iterate indicates an expected call of Iterate. +func (mr *MockStorageMockRecorder) Iterate(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Iterate", reflect.TypeOf((*MockStorage)(nil).Iterate), arg0, arg1) +} + +// Prepare mocks base method. +func (m *MockStorage) Prepare() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Prepare") + ret0, _ := ret[0].(error) + return ret0 +} + +// Prepare indicates an expected call of Prepare. +func (mr *MockStorageMockRecorder) Prepare() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Prepare", reflect.TypeOf((*MockStorage)(nil).Prepare)) +} + +// Set mocks base method. +func (m *MockStorage) Set(arg0 context.Context, arg1 string, arg2 []byte) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Set", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// Set indicates an expected call of Set. +func (mr *MockStorageMockRecorder) Set(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Set", reflect.TypeOf((*MockStorage)(nil).Set), arg0, arg1, arg2) +} + +// SetRaw mocks base method. +func (m *MockStorage) SetRaw(arg0 context.Context, arg1 ...*spacesyncproto.StoreKeyValue) error { + m.ctrl.T.Helper() + varargs := []any{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "SetRaw", varargs...) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetRaw indicates an expected call of SetRaw. +func (mr *MockStorageMockRecorder) SetRaw(arg0 any, arg1 ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetRaw", reflect.TypeOf((*MockStorage)(nil).SetRaw), varargs...) +} diff --git a/commonspace/object/keyvalue/keyvaluestorage/storage.go b/commonspace/object/keyvalue/keyvaluestorage/storage.go new file mode 100644 index 00000000..677c138e --- /dev/null +++ b/commonspace/object/keyvalue/keyvaluestorage/storage.go @@ -0,0 +1,367 @@ +//go:generate mockgen -destination mock_keyvaluestorage/mock_keyvaluestorage.go github.com/anyproto/any-sync/commonspace/object/keyvalue/keyvaluestorage Storage +package keyvaluestorage + +import ( + "context" + "encoding/binary" + "fmt" + "sync" + "time" + + anystore "github.com/anyproto/any-store" + "go.uber.org/zap" + + "github.com/anyproto/any-sync/app" + "github.com/anyproto/any-sync/app/logger" + "github.com/anyproto/any-sync/commonspace/headsync/headstorage" + "github.com/anyproto/any-sync/commonspace/object/accountdata" + "github.com/anyproto/any-sync/commonspace/object/acl/list" + "github.com/anyproto/any-sync/commonspace/object/keyvalue/keyvaluestorage/innerstorage" + "github.com/anyproto/any-sync/commonspace/object/keyvalue/keyvaluestorage/syncstorage" + "github.com/anyproto/any-sync/commonspace/spacesyncproto" + "github.com/anyproto/any-sync/util/crypto" + "github.com/anyproto/any-sync/util/slice" +) + +var log = logger.NewNamed("common.keyvalue.keyvaluestorage") + +const IndexerCName = "common.keyvalue.indexer" + +type Indexer interface { + app.Component + Index(decryptor Decryptor, keyValue ...innerstorage.KeyValue) error +} + +type Decryptor = func(kv innerstorage.KeyValue) (value []byte, err error) + +type NoOpIndexer struct{} + +func (n NoOpIndexer) Init(a *app.App) (err error) { + return nil +} + +func (n NoOpIndexer) Name() (name string) { + return IndexerCName +} + +func (n NoOpIndexer) Index(decryptor Decryptor, keyValue ...innerstorage.KeyValue) error { + return nil +} + +type Storage interface { + Id() string + Prepare() error + Set(ctx context.Context, key string, value []byte) error + SetRaw(ctx context.Context, keyValue ...*spacesyncproto.StoreKeyValue) error + GetAll(ctx context.Context, key string, get func(decryptor Decryptor, values []innerstorage.KeyValue) error) error + Iterate(ctx context.Context, f func(decryptor Decryptor, key string, values []innerstorage.KeyValue) (bool, error)) error + InnerStorage() innerstorage.KeyValueStorage +} + +type storage struct { + inner innerstorage.KeyValueStorage + keys *accountdata.AccountKeys + aclList list.AclList + syncClient syncstorage.SyncClient + indexer Indexer + storageId string + byteRepr []byte + readKeys map[string]crypto.SymKey + currentReadKey crypto.SymKey + mx sync.Mutex +} + +func New( + ctx context.Context, + storageId string, + store anystore.DB, + headStorage headstorage.HeadStorage, + keys *accountdata.AccountKeys, + syncClient syncstorage.SyncClient, + aclList list.AclList, + indexer Indexer, +) (Storage, error) { + inner, err := innerstorage.New(ctx, storageId, headStorage, store) + if err != nil { + return nil, err + } + s := &storage{ + inner: inner, + keys: keys, + storageId: storageId, + aclList: aclList, + indexer: indexer, + syncClient: syncClient, + byteRepr: make([]byte, 8), + readKeys: make(map[string]crypto.SymKey), + } + return s, nil +} + +func (s *storage) Prepare() error { + s.aclList.RLock() + defer s.aclList.RUnlock() + return s.readKeysFromAclState(s.aclList.AclState()) +} + +func (s *storage) Id() string { + return s.storageId +} + +func (s *storage) Set(ctx context.Context, key string, value []byte) error { + s.mx.Lock() + defer s.mx.Unlock() + s.aclList.RLock() + headId := s.aclList.Head().Id + state := s.aclList.AclState() + if !s.aclList.AclState().Permissions(state.Identity()).CanWrite() { + s.aclList.RUnlock() + return list.ErrInsufficientPermissions + } + readKeyId := state.CurrentReadKeyId() + err := s.readKeysFromAclState(state) + if err != nil { + s.aclList.RUnlock() + return err + } + s.aclList.RUnlock() + value, err = s.currentReadKey.Encrypt(value) + if err != nil { + return err + } + peerIdKey := s.keys.PeerKey + identityKey := s.keys.SignKey + protoPeerKey, err := peerIdKey.GetPublic().Marshall() + if err != nil { + return err + } + protoIdentityKey, err := identityKey.GetPublic().Marshall() + if err != nil { + return err + } + timestampMicro := time.Now().UnixMicro() + inner := spacesyncproto.StoreKeyInner{ + Peer: protoPeerKey, + Identity: protoIdentityKey, + Value: value, + TimestampMicro: timestampMicro, + AclHeadId: headId, + Key: key, + } + innerBytes, err := inner.MarshalVT() + if err != nil { + return err + } + peerSig, err := peerIdKey.Sign(innerBytes) + if err != nil { + return err + } + identitySig, err := identityKey.Sign(innerBytes) + if err != nil { + return err + } + keyPeerId := key + "-" + peerIdKey.GetPublic().PeerId() + keyValue := innerstorage.KeyValue{ + KeyPeerId: keyPeerId, + Key: key, + TimestampMilli: int(timestampMicro), + Identity: identityKey.GetPublic().Account(), + PeerId: peerIdKey.GetPublic().PeerId(), + AclId: headId, + ReadKeyId: readKeyId, + Value: innerstorage.Value{ + Value: innerBytes, + PeerSignature: peerSig, + IdentitySignature: identitySig, + }, + } + err = s.inner.Set(ctx, keyValue) + if err != nil { + return err + } + indexErr := s.indexer.Index(s.decrypt, keyValue) + if indexErr != nil { + log.Warn("failed to index for key", zap.String("key", key), zap.Error(indexErr)) + } + sendErr := s.syncClient.Broadcast(ctx, s.storageId, keyValue) + if sendErr != nil { + log.Warn("failed to send key value", zap.String("key", key), zap.Error(sendErr)) + } + return nil +} + +func (s *storage) SetRaw(ctx context.Context, keyValue ...*spacesyncproto.StoreKeyValue) (err error) { + if len(keyValue) == 0 { + return nil + } + s.mx.Lock() + defer s.mx.Unlock() + keyValues := make([]innerstorage.KeyValue, 0, len(keyValue)) + for _, kv := range keyValue { + innerKv, err := innerstorage.KeyValueFromProto(kv, true) + if err != nil { + return err + } + keyValues = append(keyValues, innerKv) + } + s.aclList.RLock() + state := s.aclList.AclState() + err = s.readKeysFromAclState(state) + if err != nil { + s.aclList.RUnlock() + return err + } + for i := range keyValues { + el, err := s.inner.Diff().Element(keyValues[i].KeyPeerId) + if err == nil { + binary.BigEndian.PutUint64(s.byteRepr, uint64(keyValues[i].TimestampMilli)) + if el.Head >= string(s.byteRepr) { + keyValues[i].KeyPeerId = "" + continue + } + } + keyValues[i].ReadKeyId, err = state.ReadKeyForAclId(keyValues[i].AclId) + if err != nil { + keyValues[i].KeyPeerId = "" + continue + } + } + s.aclList.RUnlock() + keyValues = slice.DiscardFromSlice(keyValues, func(value innerstorage.KeyValue) bool { + return value.KeyPeerId == "" + }) + if len(keyValues) == 0 { + return nil + } + err = s.inner.Set(ctx, keyValues...) + if err != nil { + return err + } + sendErr := s.syncClient.Broadcast(ctx, s.storageId, keyValues...) + if sendErr != nil { + log.Warn("failed to send key values", zap.Error(sendErr)) + } + indexErr := s.indexer.Index(s.decrypt, keyValues...) + if indexErr != nil { + log.Warn("failed to index for keys", zap.Error(indexErr)) + } + return nil +} + +func (s *storage) GetAll(ctx context.Context, key string, get func(decryptor Decryptor, values []innerstorage.KeyValue) error) (err error) { + var values []innerstorage.KeyValue + err = s.inner.IteratePrefix(ctx, key, func(kv innerstorage.KeyValue) error { + bytes := make([]byte, len(kv.Value.Value)) + copy(bytes, kv.Value.Value) + kv.Value.Value = bytes + values = append(values, kv) + return nil + }) + if err != nil { + return err + } + s.mx.Lock() + defer s.mx.Unlock() + return get(s.decrypt, values) +} + +func (s *storage) InnerStorage() innerstorage.KeyValueStorage { + return s.inner +} + +func (s *storage) readKeysFromAclState(state *list.AclState) (err error) { + if len(s.readKeys) == len(state.Keys()) { + return nil + } + if state.AccountKey() == nil || !state.HadReadPermissions(state.AccountKey().GetPublic()) { + return nil + } + for key, value := range state.Keys() { + if _, exists := s.readKeys[key]; exists { + continue + } + if value.ReadKey == nil { + continue + } + treeKey, err := deriveKey(value.ReadKey, s.storageId) + if err != nil { + return err + } + s.readKeys[key] = treeKey + } + curKey, err := state.CurrentReadKey() + if err != nil { + return err + } + if curKey == nil { + return nil + } + s.currentReadKey, err = deriveKey(curKey, s.storageId) + return err +} + +func (s *storage) Iterate(ctx context.Context, f func(decryptor Decryptor, key string, values []innerstorage.KeyValue) (bool, error)) (err error) { + s.mx.Lock() + defer s.mx.Unlock() + var ( + curKey = "" + // TODO: reuse buffer + values []innerstorage.KeyValue + ) + err = s.inner.IterateValues(ctx, func(kv innerstorage.KeyValue) (bool, error) { + if kv.Key != curKey { + if curKey != "" { + iter, err := f(s.decrypt, curKey, values) + if err != nil { + return false, err + } + if !iter { + values = nil + return false, nil + } + } + curKey = kv.Key + values = values[:0] + } + bytes := make([]byte, len(kv.Value.Value)) + copy(bytes, kv.Value.Value) + kv.Value.Value = bytes + values = append(values, kv) + return true, nil + }) + if err != nil { + return err + } + if len(values) > 0 { + _, err = f(s.decrypt, curKey, values) + } + return err +} + +func (s *storage) decrypt(kv innerstorage.KeyValue) (value []byte, err error) { + if kv.ReadKeyId == "" { + return nil, fmt.Errorf("no read key id") + } + key := s.readKeys[kv.ReadKeyId] + if key == nil { + return nil, fmt.Errorf("no read key for %s", kv.ReadKeyId) + } + msg := &spacesyncproto.StoreKeyInner{} + err = msg.UnmarshalVT(kv.Value.Value) + if err != nil { + return nil, err + } + value, err = key.Decrypt(msg.Value) + if err != nil { + return nil, err + } + return value, nil +} + +func deriveKey(key crypto.SymKey, id string) (crypto.SymKey, error) { + raw, err := key.Raw() + if err != nil { + return nil, err + } + return crypto.DeriveSymmetricKey(raw, fmt.Sprintf(crypto.AnysyncKeyValuePath, id)) +} diff --git a/commonspace/object/keyvalue/keyvaluestorage/syncstorage/syncclient.go b/commonspace/object/keyvalue/keyvaluestorage/syncstorage/syncclient.go new file mode 100644 index 00000000..ac284322 --- /dev/null +++ b/commonspace/object/keyvalue/keyvaluestorage/syncstorage/syncclient.go @@ -0,0 +1,83 @@ +package syncstorage + +import ( + "context" + "fmt" + + "github.com/anyproto/any-sync/commonspace/object/keyvalue/keyvaluestorage/innerstorage" + "github.com/anyproto/any-sync/commonspace/spacesyncproto" + "github.com/anyproto/any-sync/commonspace/sync" + "github.com/anyproto/any-sync/commonspace/sync/objectsync/objectmessages" +) + +type innerUpdate struct { + prepared []byte + keyValues []innerstorage.KeyValue +} + +func (i *innerUpdate) Marshall(data objectmessages.ObjectMeta) ([]byte, error) { + if i.prepared != nil { + return i.prepared, nil + } + return nil, fmt.Errorf("no prepared data") +} + +func (i *innerUpdate) Prepare() error { + // TODO: Add peer to ignored peers list + var ( + protoKeyValues []*spacesyncproto.StoreKeyValue + err error + ) + for _, kv := range i.keyValues { + protoKeyValues = append(protoKeyValues, kv.Proto()) + } + keyValues := &spacesyncproto.StoreKeyValues{KeyValues: protoKeyValues} + i.prepared, err = keyValues.MarshalVT() + return err +} + +func (i *innerUpdate) Heads() []string { + return nil +} + +func (i *innerUpdate) MsgSize() uint64 { + return uint64(len(i.prepared)) +} + +func (i *innerUpdate) ObjectType() spacesyncproto.ObjectType { + return spacesyncproto.ObjectType_KeyValue +} + +type SyncClient interface { + Broadcast(ctx context.Context, objectId string, keyValues ...innerstorage.KeyValue) error +} + +type syncClient struct { + spaceId string + syncService sync.SyncService +} + +func New(spaceId string, syncService sync.SyncService) SyncClient { + return &syncClient{ + spaceId: spaceId, + syncService: syncService, + } +} + +func (s *syncClient) Broadcast(ctx context.Context, objectId string, keyValue ...innerstorage.KeyValue) error { + inner := &innerUpdate{ + keyValues: keyValue, + } + err := inner.Prepare() + if err != nil { + return err + } + headUpdate := &objectmessages.HeadUpdate{ + Meta: objectmessages.ObjectMeta{ + ObjectId: objectId, + SpaceId: s.spaceId, + }, + Update: inner, + } + return s.syncService.BroadcastMessage(ctx, headUpdate) +} diff --git a/commonspace/object/keyvalue/kvinterfaces/interfaces.go b/commonspace/object/keyvalue/kvinterfaces/interfaces.go new file mode 100644 index 00000000..ce0ea4b3 --- /dev/null +++ b/commonspace/object/keyvalue/kvinterfaces/interfaces.go @@ -0,0 +1,24 @@ +//go:generate mockgen -destination mock_kvinterfaces/mock_kvinterfaces.go github.com/anyproto/any-sync/commonspace/object/keyvalue/kvinterfaces KeyValueService +package kvinterfaces + +import ( + "context" + + "storj.io/drpc" + + "github.com/anyproto/any-sync/app" + "github.com/anyproto/any-sync/commonspace/object/keyvalue/keyvaluestorage" + "github.com/anyproto/any-sync/commonspace/spacesyncproto" + "github.com/anyproto/any-sync/net/peer" +) + +const CName = "common.object.keyvalue" + +type KeyValueService interface { + app.ComponentRunnable + DefaultStore() keyvaluestorage.Storage + HandleMessage(ctx context.Context, msg drpc.Message) (err error) + SyncWithPeer(p peer.Peer) (err error) + HandleStoreDiffRequest(ctx context.Context, req *spacesyncproto.StoreDiffRequest) (resp *spacesyncproto.StoreDiffResponse, err error) + HandleStoreElementsRequest(ctx context.Context, stream spacesyncproto.DRPCSpaceSync_StoreElementsStream) (err error) +} diff --git a/commonspace/object/keyvalue/kvinterfaces/mock_kvinterfaces/mock_kvinterfaces.go b/commonspace/object/keyvalue/kvinterfaces/mock_kvinterfaces/mock_kvinterfaces.go new file mode 100644 index 00000000..93026984 --- /dev/null +++ b/commonspace/object/keyvalue/kvinterfaces/mock_kvinterfaces/mock_kvinterfaces.go @@ -0,0 +1,171 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/anyproto/any-sync/commonspace/object/keyvalue/kvinterfaces (interfaces: KeyValueService) +// +// Generated by this command: +// +// mockgen -destination mock_kvinterfaces/mock_kvinterfaces.go github.com/anyproto/any-sync/commonspace/object/keyvalue/kvinterfaces KeyValueService +// +// Package mock_kvinterfaces is a generated GoMock package. +package mock_kvinterfaces + +import ( + context "context" + reflect "reflect" + + app "github.com/anyproto/any-sync/app" + keyvaluestorage "github.com/anyproto/any-sync/commonspace/object/keyvalue/keyvaluestorage" + spacesyncproto "github.com/anyproto/any-sync/commonspace/spacesyncproto" + peer "github.com/anyproto/any-sync/net/peer" + gomock "go.uber.org/mock/gomock" + drpc "storj.io/drpc" +) + +// MockKeyValueService is a mock of KeyValueService interface. +type MockKeyValueService struct { + ctrl *gomock.Controller + recorder *MockKeyValueServiceMockRecorder +} + +// MockKeyValueServiceMockRecorder is the mock recorder for MockKeyValueService. +type MockKeyValueServiceMockRecorder struct { + mock *MockKeyValueService +} + +// NewMockKeyValueService creates a new mock instance. +func NewMockKeyValueService(ctrl *gomock.Controller) *MockKeyValueService { + mock := &MockKeyValueService{ctrl: ctrl} + mock.recorder = &MockKeyValueServiceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockKeyValueService) EXPECT() *MockKeyValueServiceMockRecorder { + return m.recorder +} + +// Close mocks base method. +func (m *MockKeyValueService) Close(arg0 context.Context) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Close", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close. +func (mr *MockKeyValueServiceMockRecorder) Close(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockKeyValueService)(nil).Close), arg0) +} + +// DefaultStore mocks base method. +func (m *MockKeyValueService) DefaultStore() keyvaluestorage.Storage { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultStore") + ret0, _ := ret[0].(keyvaluestorage.Storage) + return ret0 +} + +// DefaultStore indicates an expected call of DefaultStore. +func (mr *MockKeyValueServiceMockRecorder) DefaultStore() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultStore", reflect.TypeOf((*MockKeyValueService)(nil).DefaultStore)) +} + +// HandleMessage mocks base method. +func (m *MockKeyValueService) HandleMessage(arg0 context.Context, arg1 drpc.Message) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HandleMessage", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// HandleMessage indicates an expected call of HandleMessage. +func (mr *MockKeyValueServiceMockRecorder) HandleMessage(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleMessage", reflect.TypeOf((*MockKeyValueService)(nil).HandleMessage), arg0, arg1) +} + +// HandleStoreDiffRequest mocks base method. +func (m *MockKeyValueService) HandleStoreDiffRequest(arg0 context.Context, arg1 *spacesyncproto.StoreDiffRequest) (*spacesyncproto.StoreDiffResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HandleStoreDiffRequest", arg0, arg1) + ret0, _ := ret[0].(*spacesyncproto.StoreDiffResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// HandleStoreDiffRequest indicates an expected call of HandleStoreDiffRequest. +func (mr *MockKeyValueServiceMockRecorder) HandleStoreDiffRequest(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleStoreDiffRequest", reflect.TypeOf((*MockKeyValueService)(nil).HandleStoreDiffRequest), arg0, arg1) +} + +// HandleStoreElementsRequest mocks base method. +func (m *MockKeyValueService) HandleStoreElementsRequest(arg0 context.Context, arg1 spacesyncproto.DRPCSpaceSync_StoreElementsStream) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HandleStoreElementsRequest", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// HandleStoreElementsRequest indicates an expected call of HandleStoreElementsRequest. +func (mr *MockKeyValueServiceMockRecorder) HandleStoreElementsRequest(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleStoreElementsRequest", reflect.TypeOf((*MockKeyValueService)(nil).HandleStoreElementsRequest), arg0, arg1) +} + +// Init mocks base method. +func (m *MockKeyValueService) Init(arg0 *app.App) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Init", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Init indicates an expected call of Init. +func (mr *MockKeyValueServiceMockRecorder) Init(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Init", reflect.TypeOf((*MockKeyValueService)(nil).Init), arg0) +} + +// Name mocks base method. +func (m *MockKeyValueService) Name() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Name") + ret0, _ := ret[0].(string) + return ret0 +} + +// Name indicates an expected call of Name. +func (mr *MockKeyValueServiceMockRecorder) Name() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockKeyValueService)(nil).Name)) +} + +// Run mocks base method. +func (m *MockKeyValueService) Run(arg0 context.Context) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Run", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Run indicates an expected call of Run. +func (mr *MockKeyValueServiceMockRecorder) Run(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Run", reflect.TypeOf((*MockKeyValueService)(nil).Run), arg0) +} + +// SyncWithPeer mocks base method. +func (m *MockKeyValueService) SyncWithPeer(arg0 peer.Peer) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SyncWithPeer", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// SyncWithPeer indicates an expected call of SyncWithPeer. +func (mr *MockKeyValueServiceMockRecorder) SyncWithPeer(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SyncWithPeer", reflect.TypeOf((*MockKeyValueService)(nil).SyncWithPeer), arg0) +} diff --git a/commonspace/object/keyvalue/limiter.go b/commonspace/object/keyvalue/limiter.go new file mode 100644 index 00000000..7a36bffd --- /dev/null +++ b/commonspace/object/keyvalue/limiter.go @@ -0,0 +1,52 @@ +package keyvalue + +import ( + "context" + "sync" +) + +type concurrentLimiter struct { + mu sync.Mutex + inProgress map[string]bool + wg sync.WaitGroup +} + +func newConcurrentLimiter() *concurrentLimiter { + return &concurrentLimiter{ + inProgress: make(map[string]bool), + } +} + +func (cl *concurrentLimiter) ScheduleRequest(ctx context.Context, id string, action func()) bool { + cl.mu.Lock() + if cl.inProgress[id] { + cl.mu.Unlock() + return false + } + + cl.inProgress[id] = true + cl.wg.Add(1) + cl.mu.Unlock() + + go func() { + defer func() { + cl.mu.Lock() + delete(cl.inProgress, id) + cl.mu.Unlock() + cl.wg.Done() + }() + + select { + case <-ctx.Done(): + return + default: + action() + } + }() + + return true +} + +func (cl *concurrentLimiter) Close() { + cl.wg.Wait() +} diff --git a/commonspace/object/keyvalue/remotediff.go b/commonspace/object/keyvalue/remotediff.go new file mode 100644 index 00000000..c0b82e10 --- /dev/null +++ b/commonspace/object/keyvalue/remotediff.go @@ -0,0 +1,106 @@ +package keyvalue + +import ( + "context" + + "github.com/anyproto/any-sync/app/ldiff" + "github.com/anyproto/any-sync/commonspace/spacesyncproto" +) + +type Client interface { + StoreDiff(context.Context, *spacesyncproto.StoreDiffRequest) (*spacesyncproto.StoreDiffResponse, error) +} + +type RemoteDiff interface { + ldiff.Remote +} + +func NewRemoteDiff(spaceId string, client Client) RemoteDiff { + return &remote{ + spaceId: spaceId, + client: client, + } +} + +type remote struct { + spaceId string + client Client +} + +func (r *remote) Ranges(ctx context.Context, ranges []ldiff.Range, resBuf []ldiff.RangeResult) (results []ldiff.RangeResult, err error) { + results = resBuf[:0] + pbRanges := make([]*spacesyncproto.HeadSyncRange, 0, len(ranges)) + for _, rg := range ranges { + pbRanges = append(pbRanges, &spacesyncproto.HeadSyncRange{ + From: rg.From, + To: rg.To, + Elements: rg.Elements, + Limit: uint32(rg.Limit), + }) + } + req := &spacesyncproto.StoreDiffRequest{ + SpaceId: r.spaceId, + Ranges: pbRanges, + } + resp, err := r.client.StoreDiff(ctx, req) + if err != nil { + return + } + for _, rr := range resp.Results { + var elms []ldiff.Element + if len(rr.Elements) > 0 { + elms = make([]ldiff.Element, 0, len(rr.Elements)) + } + for _, e := range rr.Elements { + elms = append(elms, ldiff.Element{ + Id: e.Id, + Head: e.Head, + }) + } + results = append(results, ldiff.RangeResult{ + Hash: rr.Hash, + Elements: elms, + Count: int(rr.Count), + }) + } + return +} + +func HandleRangeRequest(ctx context.Context, d ldiff.Diff, req *spacesyncproto.StoreDiffRequest) (resp *spacesyncproto.StoreDiffResponse, err error) { + ranges := make([]ldiff.Range, 0, len(req.Ranges)) + // basically we gather data applicable for both diffs + for _, reqRange := range req.Ranges { + ranges = append(ranges, ldiff.Range{ + From: reqRange.From, + To: reqRange.To, + Limit: int(reqRange.Limit), + Elements: reqRange.Elements, + }) + } + res, err := d.Ranges(ctx, ranges, nil) + if err != nil { + return + } + + resp = &spacesyncproto.StoreDiffResponse{ + Results: make([]*spacesyncproto.HeadSyncResult, 0, len(res)), + } + for _, rangeRes := range res { + var elements []*spacesyncproto.HeadSyncResultElement + if len(rangeRes.Elements) > 0 { + elements = make([]*spacesyncproto.HeadSyncResultElement, 0, len(rangeRes.Elements)) + for _, el := range rangeRes.Elements { + elements = append(elements, &spacesyncproto.HeadSyncResultElement{ + Id: el.Id, + Head: el.Head, + }) + } + } + resp.Results = append(resp.Results, &spacesyncproto.HeadSyncResult{ + Hash: rangeRes.Hash, + Elements: elements, + Count: uint32(rangeRes.Count), + }) + } + return +} diff --git a/commonspace/object/tree/objecttree/storage.go b/commonspace/object/tree/objecttree/storage.go index 02edf830..2a88ad04 100644 --- a/commonspace/object/tree/objecttree/storage.go +++ b/commonspace/object/tree/objecttree/storage.go @@ -82,12 +82,8 @@ func CreateStorage(ctx context.Context, root *treechangeproto.RawTreeChangeWithI return nil, err } storage, err := CreateStorageTx(tx.Context(), root, headStorage, store) - defer func() { - if err != nil { - tx.Rollback() - } - }() if err != nil { + tx.Rollback() return nil, err } return storage, tx.Commit() @@ -225,13 +221,19 @@ func (s *storage) AddAll(ctx context.Context, changes []StorageChange, heads []s if err != nil { return fmt.Errorf("failed to create write tx: %w", err) } + defer func() { + if err != nil { + tx.Rollback() + } else { + err = tx.Commit() + } + }() for _, ch := range changes { ch.TreeId = s.id newVal := newStorageChangeValue(ch, arena) err = s.changesColl.Insert(tx.Context(), newVal) arena.Reset() if err != nil { - tx.Rollback() return err } } @@ -240,12 +242,7 @@ func (s *storage) AddAll(ctx context.Context, changes []StorageChange, heads []s Heads: heads, CommonSnapshot: &commonSnapshot, } - err = s.headStorage.UpdateEntryTx(tx.Context(), update) - if err != nil { - tx.Rollback() - return err - } - return tx.Commit() + return s.headStorage.UpdateEntryTx(tx.Context(), update) } func (s *storage) AddAllNoError(ctx context.Context, changes []StorageChange, heads []string, commonSnapshot string) error { @@ -255,13 +252,19 @@ func (s *storage) AddAllNoError(ctx context.Context, changes []StorageChange, he if err != nil { return fmt.Errorf("failed to create write tx: %w", err) } + defer func() { + if err != nil { + tx.Rollback() + } else { + err = tx.Commit() + } + }() for _, ch := range changes { ch.TreeId = s.id newVal := newStorageChangeValue(ch, arena) err = s.changesColl.Insert(tx.Context(), newVal) arena.Reset() if err != nil && !errors.Is(err, anystore.ErrDocExists) { - tx.Rollback() return err } } @@ -270,12 +273,7 @@ func (s *storage) AddAllNoError(ctx context.Context, changes []StorageChange, he Heads: heads, CommonSnapshot: &commonSnapshot, } - err = s.headStorage.UpdateEntryTx(tx.Context(), update) - if err != nil { - tx.Rollback() - return err - } - return tx.Commit() + return s.headStorage.UpdateEntryTx(tx.Context(), update) } func (s *storage) Delete(ctx context.Context) error { diff --git a/commonspace/object/tree/synctree/headupdate.go b/commonspace/object/tree/synctree/headupdate.go index b1e02016..f088a852 100644 --- a/commonspace/object/tree/synctree/headupdate.go +++ b/commonspace/object/tree/synctree/headupdate.go @@ -4,6 +4,7 @@ import ( "slices" "github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto" + "github.com/anyproto/any-sync/commonspace/spacesyncproto" "github.com/anyproto/any-sync/commonspace/sync/objectsync/objectmessages" ) @@ -21,6 +22,10 @@ func (h *InnerHeadUpdate) MsgSize() (size uint64) { return uint64(len(h.prepared)) } +func (h *InnerHeadUpdate) ObjectType() spacesyncproto.ObjectType { + return spacesyncproto.ObjectType_Tree +} + func (h *InnerHeadUpdate) Prepare() error { treeMsg := treechangeproto.WrapHeadUpdate(&treechangeproto.TreeHeadUpdate{ Heads: h.heads, diff --git a/commonspace/space.go b/commonspace/space.go index 7325ccb3..8ea543bf 100644 --- a/commonspace/space.go +++ b/commonspace/space.go @@ -16,6 +16,7 @@ import ( "github.com/anyproto/any-sync/commonspace/headsync/headstorage" "github.com/anyproto/any-sync/commonspace/object/acl/list" "github.com/anyproto/any-sync/commonspace/object/acl/syncacl" + "github.com/anyproto/any-sync/commonspace/object/keyvalue/kvinterfaces" "github.com/anyproto/any-sync/commonspace/object/treesyncer" "github.com/anyproto/any-sync/commonspace/objecttreebuilder" "github.com/anyproto/any-sync/commonspace/peermanager" @@ -28,35 +29,8 @@ import ( "github.com/anyproto/any-sync/commonspace/syncstatus" "github.com/anyproto/any-sync/net/peer" "github.com/anyproto/any-sync/net/streampool" - "github.com/anyproto/any-sync/util/crypto" ) -type SpaceCreatePayload struct { - // SigningKey is the signing key of the owner - SigningKey crypto.PrivKey - // SpaceType is an arbitrary string - SpaceType string - // ReplicationKey is a key which is to be used to determine the node where the space should be held - ReplicationKey uint64 - // SpacePayload is an arbitrary payload related to space type - SpacePayload []byte - // MasterKey is the master key of the owner - MasterKey crypto.PrivKey - // ReadKey is the first read key of space - ReadKey crypto.SymKey - // MetadataKey is the first metadata key of space - MetadataKey crypto.PrivKey - // Metadata is the metadata of the owner - Metadata []byte -} - -type SpaceDerivePayload struct { - SigningKey crypto.PrivKey - MasterKey crypto.PrivKey - SpaceType string - SpacePayload []byte -} - type SpaceDescription struct { SpaceHeader *spacesyncproto.RawSpaceHeaderWithId AclId string @@ -83,6 +57,7 @@ type Space interface { AclClient() aclclient.AclSpaceClient SyncStatus() syncstatus.StatusUpdater Storage() spacestorage.SpaceStorage + KeyValue() kvinterfaces.KeyValueService DeleteTree(ctx context.Context, id string) (err error) GetNodePeers(ctx context.Context) (peer []peer.Peer, err error) @@ -110,6 +85,7 @@ type space struct { settings settings.Settings storage spacestorage.SpaceStorage aclClient aclclient.AclSpaceClient + keyValue kvinterfaces.KeyValueService aclList list.AclList creationTime time.Time } @@ -150,7 +126,7 @@ func (s *space) DebugAllHeads() (heads []headsync.TreeHeads) { s.storage.HeadStorage().IterateEntries(context.Background(), headstorage.IterOpts{}, func(entry headstorage.HeadsEntry) (bool, error) { if entry.CommonSnapshot != "" { heads = append(heads, headsync.TreeHeads{ - Id: entry.Id, + Id: entry.Id, Heads: entry.Heads, }) } @@ -221,6 +197,7 @@ func (s *space) Init(ctx context.Context) (err error) { s.streamPool = s.app.MustComponent(streampool.CName).(streampool.StreamPool) s.treeSyncer = s.app.MustComponent(treesyncer.CName).(treesyncer.TreeSyncer) s.aclClient = s.app.MustComponent(aclclient.CName).(aclclient.AclSpaceClient) + s.keyValue = s.app.MustComponent(kvinterfaces.CName).(kvinterfaces.KeyValueService) return } @@ -228,6 +205,10 @@ func (s *space) SyncStatus() syncstatus.StatusUpdater { return s.syncStatus } +func (s *space) KeyValue() kvinterfaces.KeyValueService { + return s.keyValue +} + func (s *space) Storage() spacestorage.SpaceStorage { return s.storage } diff --git a/commonspace/payloads.go b/commonspace/spacepayloads/payloads.go similarity index 88% rename from commonspace/payloads.go rename to commonspace/spacepayloads/payloads.go index 40a6b962..a0f410e8 100644 --- a/commonspace/payloads.go +++ b/commonspace/spacepayloads/payloads.go @@ -1,9 +1,9 @@ -package commonspace +package spacepayloads import ( + "crypto/rand" "errors" "hash/fnv" - "math/rand" "strconv" "strings" "time" @@ -19,6 +19,32 @@ import ( "github.com/anyproto/any-sync/util/crypto" ) +type SpaceCreatePayload struct { + // SigningKey is the signing key of the owner + SigningKey crypto.PrivKey + // SpaceType is an arbitrary string + SpaceType string + // ReplicationKey is a key which is to be used to determine the node where the space should be held + ReplicationKey uint64 + // SpacePayload is an arbitrary payload related to space type + SpacePayload []byte + // MasterKey is the master key of the owner + MasterKey crypto.PrivKey + // ReadKey is the first read key of space + ReadKey crypto.SymKey + // MetadataKey is the first metadata key of space + MetadataKey crypto.PrivKey + // Metadata is the metadata of the owner + Metadata []byte +} + +type SpaceDerivePayload struct { + SigningKey crypto.PrivKey + MasterKey crypto.PrivKey + SpaceType string + SpacePayload []byte +} + const ( SpaceReserved = "any-sync.space" ) @@ -111,7 +137,7 @@ func StoragePayloadForSpaceCreate(payload SpaceCreatePayload) (storagePayload sp return } -func storagePayloadForSpaceDerive(payload SpaceDerivePayload) (storagePayload spacestorage.SpaceStorageCreatePayload, err error) { +func StoragePayloadForSpaceDerive(payload SpaceDerivePayload) (storagePayload spacestorage.SpaceStorageCreatePayload, err error) { // marshalling keys identity, err := payload.SigningKey.GetPublic().Marshall() if err != nil { @@ -190,7 +216,7 @@ func storagePayloadForSpaceDerive(payload SpaceDerivePayload) (storagePayload sp return } -func validateSpaceStorageCreatePayload(payload spacestorage.SpaceStorageCreatePayload) (err error) { +func ValidateSpaceStorageCreatePayload(payload spacestorage.SpaceStorageCreatePayload) (err error) { err = ValidateSpaceHeader(payload.SpaceHeaderWithId, nil) if err != nil { return @@ -326,3 +352,7 @@ func validateCreateSpaceSettingsPayload(rawWithId *treechangeproto.RawTreeChange return } + +func NewSpaceId(id string, repKey uint64) string { + return strings.Join([]string{id, strconv.FormatUint(repKey, 36)}, ".") +} diff --git a/commonspace/payloads_test.go b/commonspace/spacepayloads/payloads_test.go similarity index 98% rename from commonspace/payloads_test.go rename to commonspace/spacepayloads/payloads_test.go index cc2cf179..706c4389 100644 --- a/commonspace/payloads_test.go +++ b/commonspace/spacepayloads/payloads_test.go @@ -1,4 +1,4 @@ -package commonspace +package spacepayloads import ( "fmt" @@ -7,6 +7,9 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/anyproto/any-sync/commonspace/object/accountdata" "github.com/anyproto/any-sync/commonspace/object/acl/aclrecordproto" "github.com/anyproto/any-sync/commonspace/object/tree/objecttree" @@ -16,8 +19,6 @@ import ( "github.com/anyproto/any-sync/consensus/consensusproto" "github.com/anyproto/any-sync/util/cidutil" "github.com/anyproto/any-sync/util/crypto" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestSuccessHeaderPayloadForSpaceCreate(t *testing.T) { @@ -438,7 +439,7 @@ func TestSuccessSameIds(t *testing.T) { SpaceHeaderWithId: rawHeaderWithId, SpaceSettingsWithId: rawSettingsPayload, } - err = validateSpaceStorageCreatePayload(spacePayload) + err = ValidateSpaceStorageCreatePayload(spacePayload) require.NoError(t, err) } @@ -455,7 +456,7 @@ func TestFailWithAclWrongSpaceId(t *testing.T) { SpaceHeaderWithId: rawHeaderWithId, SpaceSettingsWithId: rawSettingsPayload, } - err = validateSpaceStorageCreatePayload(spacePayload) + err = ValidateSpaceStorageCreatePayload(spacePayload) assert.EqualErrorf(t, err, spacestorage.ErrIncorrectSpaceHeader.Error(), "Error should be: %v, got: %v", spacestorage.ErrIncorrectSpaceHeader, err) } @@ -472,7 +473,7 @@ func TestFailWithSettingsWrongSpaceId(t *testing.T) { SpaceHeaderWithId: rawHeaderWithId, SpaceSettingsWithId: rawSettingsPayload, } - err = validateSpaceStorageCreatePayload(spacePayload) + err = ValidateSpaceStorageCreatePayload(spacePayload) assert.EqualErrorf(t, err, spacestorage.ErrIncorrectSpaceHeader.Error(), "Error should be: %v, got: %v", spacestorage.ErrIncorrectSpaceHeader, err) } @@ -489,7 +490,7 @@ func TestFailWithWrongAclHeadIdInSettingsPayload(t *testing.T) { SpaceHeaderWithId: rawHeaderWithId, SpaceSettingsWithId: rawSettingsPayload, } - err = validateSpaceStorageCreatePayload(spacePayload) + err = ValidateSpaceStorageCreatePayload(spacePayload) assert.EqualErrorf(t, err, spacestorage.ErrIncorrectSpaceHeader.Error(), "Error should be: %v, got: %v", spacestorage.ErrIncorrectSpaceHeader, err) } diff --git a/commonspace/spacerpc_test.go b/commonspace/spacerpc_test.go index 273ad3fd..dd44695b 100644 --- a/commonspace/spacerpc_test.go +++ b/commonspace/spacerpc_test.go @@ -93,6 +93,16 @@ type RpcServer struct { sync.Mutex } +func (r *RpcServer) StoreDiff(ctx2 context.Context, request *spacesyncproto.StoreDiffRequest) (*spacesyncproto.StoreDiffResponse, error) { + //TODO implement me + panic("implement me") +} + +func (r *RpcServer) StoreElements(stream spacesyncproto.DRPCSpaceSync_StoreElementsStream) error { + //TODO implement me + panic("implement me") +} + func NewRpcServer() *RpcServer { return &RpcServer{ spaces: make(map[string]Space), diff --git a/commonspace/spaceservice.go b/commonspace/spaceservice.go index b7e0f447..630e15c2 100644 --- a/commonspace/spaceservice.go +++ b/commonspace/spaceservice.go @@ -13,7 +13,10 @@ import ( "github.com/anyproto/any-sync/commonspace/acl/aclclient" "github.com/anyproto/any-sync/commonspace/deletionmanager" + "github.com/anyproto/any-sync/commonspace/object/keyvalue" + "github.com/anyproto/any-sync/commonspace/object/keyvalue/keyvaluestorage" "github.com/anyproto/any-sync/commonspace/object/treesyncer" + "github.com/anyproto/any-sync/commonspace/spacepayloads" "github.com/anyproto/any-sync/commonspace/sync" "github.com/anyproto/any-sync/commonspace/sync/objectsync" "github.com/anyproto/any-sync/net" @@ -58,9 +61,9 @@ type ctxKey int const AddSpaceCtxKey ctxKey = 0 type SpaceService interface { - DeriveSpace(ctx context.Context, payload SpaceDerivePayload) (string, error) - DeriveId(ctx context.Context, payload SpaceDerivePayload) (string, error) - CreateSpace(ctx context.Context, payload SpaceCreatePayload) (string, error) + DeriveSpace(ctx context.Context, payload spacepayloads.SpaceDerivePayload) (string, error) + DeriveId(ctx context.Context, payload spacepayloads.SpaceDerivePayload) (string, error) + CreateSpace(ctx context.Context, payload spacepayloads.SpaceCreatePayload) (string, error) NewSpace(ctx context.Context, id string, deps Deps) (sp Space, err error) app.Component } @@ -69,6 +72,7 @@ type Deps struct { SyncStatus syncstatus.StatusUpdater TreeSyncer treesyncer.TreeSyncer AccountService accountservice.Service + Indexer keyvaluestorage.Indexer } type spaceService struct { @@ -101,8 +105,8 @@ func (s *spaceService) Name() (name string) { return CName } -func (s *spaceService) CreateSpace(ctx context.Context, payload SpaceCreatePayload) (id string, err error) { - storageCreate, err := StoragePayloadForSpaceCreate(payload) +func (s *spaceService) CreateSpace(ctx context.Context, payload spacepayloads.SpaceCreatePayload) (id string, err error) { + storageCreate, err := spacepayloads.StoragePayloadForSpaceCreate(payload) if err != nil { return } @@ -117,8 +121,8 @@ func (s *spaceService) CreateSpace(ctx context.Context, payload SpaceCreatePaylo return store.Id(), store.Close(ctx) } -func (s *spaceService) DeriveId(ctx context.Context, payload SpaceDerivePayload) (id string, err error) { - storageCreate, err := storagePayloadForSpaceDerive(payload) +func (s *spaceService) DeriveId(ctx context.Context, payload spacepayloads.SpaceDerivePayload) (id string, err error) { + storageCreate, err := spacepayloads.StoragePayloadForSpaceDerive(payload) if err != nil { return } @@ -126,8 +130,8 @@ func (s *spaceService) DeriveId(ctx context.Context, payload SpaceDerivePayload) return } -func (s *spaceService) DeriveSpace(ctx context.Context, payload SpaceDerivePayload) (id string, err error) { - storageCreate, err := storagePayloadForSpaceDerive(payload) +func (s *spaceService) DeriveSpace(ctx context.Context, payload spacepayloads.SpaceDerivePayload) (id string, err error) { + storageCreate, err := spacepayloads.StoragePayloadForSpaceDerive(payload) if err != nil { return } @@ -180,13 +184,19 @@ func (s *spaceService) NewSpace(ctx context.Context, id string, deps Deps) (Spac if deps.AccountService != nil { spaceApp.Register(deps.AccountService) } + var keyValueIndexer keyvaluestorage.Indexer = keyvaluestorage.NoOpIndexer{} + if deps.Indexer != nil { + keyValueIndexer = deps.Indexer + } spaceApp.Register(state). Register(deps.SyncStatus). Register(peerManager). Register(st). + Register(keyValueIndexer). Register(objectsync.New()). Register(sync.NewSyncService()). Register(syncacl.New()). + Register(keyvalue.New()). Register(deletionstate.New()). Register(deletionmanager.New()). Register(settings.New()). @@ -304,7 +314,7 @@ func (s *spaceService) spacePullWithPeer(ctx context.Context, p peer.Peer, id st } func (s *spaceService) createSpaceStorage(ctx context.Context, payload spacestorage.SpaceStorageCreatePayload) (spacestorage.SpaceStorage, error) { - err := validateSpaceStorageCreatePayload(payload) + err := spacepayloads.ValidateSpaceStorageCreatePayload(payload) if err != nil { return nil, err } diff --git a/commonspace/spacestorage/migration/spacemigrator.go b/commonspace/spacestorage/migration/spacemigrator.go index 57885ff5..0eb9c221 100644 --- a/commonspace/spacestorage/migration/spacemigrator.go +++ b/commonspace/spacestorage/migration/spacemigrator.go @@ -4,8 +4,6 @@ import ( "context" "errors" "fmt" - "os" - "path/filepath" "time" anystore "github.com/anyproto/any-store" @@ -30,14 +28,13 @@ var ErrAlreadyMigrated = errors.New("already migrated") type SpaceMigrator interface { MigrateId(ctx context.Context, id string, progress Progress) error - CheckMigrated(ctx context.Context, id string) (bool, error) } type Progress interface { AddDone(done int64) } -type RemoveFunc func(newStorage spacestorage.SpaceStorage, rootPath string) error +type RemoveFunc func(newStorage spacestorage.SpaceStorage, id, rootPath string) error type spaceMigrator struct { oldProvider oldstorage.SpaceStorageProvider @@ -47,11 +44,7 @@ type spaceMigrator struct { removeFunc RemoveFunc } -func NewSpaceMigrator(oldProvider oldstorage.SpaceStorageProvider, newProvider spacestorage.SpaceStorageProvider, numParallel int, rootPath string) SpaceMigrator { - return NewSpaceMigratorWithRemoveFunc(oldProvider, newProvider, numParallel, rootPath, nil) -} - -func NewSpaceMigratorWithRemoveFunc(oldProvider oldstorage.SpaceStorageProvider, newProvider spacestorage.SpaceStorageProvider, numParallel int, rootPath string, removeFunc RemoveFunc) SpaceMigrator { +func NewSpaceMigrator(oldProvider oldstorage.SpaceStorageProvider, newProvider spacestorage.SpaceStorageProvider, numParallel int, rootPath string, removeFunc RemoveFunc) SpaceMigrator { return &spaceMigrator{ oldProvider: oldProvider, newProvider: newProvider, @@ -61,33 +54,15 @@ func NewSpaceMigratorWithRemoveFunc(oldProvider oldstorage.SpaceStorageProvider, } } -func (s *spaceMigrator) CheckMigrated(ctx context.Context, id string) (bool, error) { - migrated, storage := s.checkMigrated(ctx, id) - if storage != nil { - return migrated, storage.Close(ctx) - } - return false, nil -} - func (s *spaceMigrator) MigrateId(ctx context.Context, id string, progress Progress) error { migrated, storage := s.checkMigrated(ctx, id) if migrated { storage.Close(ctx) return ErrAlreadyMigrated } - if storage != nil { - if s.removeFunc != nil { - err := s.removeFunc(storage, s.rootPath) - if err != nil { - return fmt.Errorf("migration: failed to remove new storage: %w", err) - } - } else { - err := storage.Close(ctx) - if err != nil { - return fmt.Errorf("migration: failed to close old storage: %w", err) - } - os.RemoveAll(filepath.Join(s.rootPath, id)) - } + err := s.removeFunc(storage, id, s.rootPath) + if err != nil { + return fmt.Errorf("migration: failed to remove new storage: %w", err) } oldStorage, err := s.oldProvider.WaitSpaceStorage(ctx, id) if err != nil { @@ -146,7 +121,6 @@ func (s *spaceMigrator) MigrateId(ctx context.Context, id string, progress Progr treeMigrators = append(treeMigrators, objecttree.NewTreeMigrator(crypto.NewKeyStorage(), aclList)) ch <- treeMigrators[i] } - var allErrors []error slices.Sort(storedIds) storedIds = slice.DiscardDuplicatesSorted(storedIds) for _, id := range storedIds { @@ -163,7 +137,6 @@ func (s *spaceMigrator) MigrateId(ctx context.Context, id string, progress Progr } err = tm.MigrateTreeStorage(ctx, treeStorage, newStorage.HeadStorage(), newStorage.AnyStore()) if err != nil { - allErrors = append(allErrors, fmt.Errorf("migration: failed to migrate tree storage: %w", err)) return } }) @@ -176,9 +149,6 @@ func (s *spaceMigrator) MigrateId(ctx context.Context, id string, progress Progr if err != nil { return fmt.Errorf("migration: failed to wait for executor: %w", err) } - if len(allErrors) > 0 { - return fmt.Errorf("migration failed: %w", errors.Join(allErrors...)) - } if err := s.migrateHash(ctx, oldStorage, newStorage); err != nil { log.Warn("migration: failed to migrate hash", zap.Error(err)) } diff --git a/commonspace/spacestorage/spacestorage.go b/commonspace/spacestorage/spacestorage.go index fac0f398..2c3a5a7a 100644 --- a/commonspace/spacestorage/spacestorage.go +++ b/commonspace/spacestorage/spacestorage.go @@ -66,7 +66,9 @@ func Create(ctx context.Context, store anystore.DB, payload SpaceStorageCreatePa } defer func() { if err != nil { - tx.Rollback() + _ = tx.Rollback() + } else { + err = tx.Commit() } }() changesColl, err := store.Collection(tx.Context(), objecttree.CollName) @@ -110,7 +112,7 @@ func Create(ctx context.Context, store anystore.DB, payload SpaceStorageCreatePa headStorage: headStorage, stateStorage: stateStorage, aclStorage: aclStorage, - }, tx.Commit() + }, nil } func New(ctx context.Context, spaceId string, store anystore.DB) (SpaceStorage, error) { diff --git a/commonspace/spacestorage_test.go b/commonspace/spacestorage_test.go index 51059d51..a7cc038f 100644 --- a/commonspace/spacestorage_test.go +++ b/commonspace/spacestorage_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/require" "github.com/anyproto/any-sync/commonspace/object/accountdata" + "github.com/anyproto/any-sync/commonspace/spacepayloads" "github.com/anyproto/any-sync/commonspace/spacestorage" "github.com/anyproto/any-sync/util/crypto" ) @@ -22,7 +23,7 @@ func newStorageCreatePayload(t *testing.T) spacestorage.SpaceStorageCreatePayloa require.NoError(t, err) readKey := crypto.NewAES() meta := []byte("account") - payload := SpaceCreatePayload{ + payload := spacepayloads.SpaceCreatePayload{ SigningKey: keys.SignKey, SpaceType: "space", ReplicationKey: 10, @@ -32,7 +33,7 @@ func newStorageCreatePayload(t *testing.T) spacestorage.SpaceStorageCreatePayloa MetadataKey: metaKey, Metadata: meta, } - createSpace, err := StoragePayloadForSpaceCreate(payload) + createSpace, err := spacepayloads.StoragePayloadForSpaceCreate(payload) require.NoError(t, err) return createSpace } diff --git a/commonspace/spacesyncproto/mock_spacesyncproto/mock_spacesyncproto.go b/commonspace/spacesyncproto/mock_spacesyncproto/mock_spacesyncproto.go index 8f01d440..c9e6fd57 100644 --- a/commonspace/spacesyncproto/mock_spacesyncproto/mock_spacesyncproto.go +++ b/commonspace/spacesyncproto/mock_spacesyncproto/mock_spacesyncproto.go @@ -175,3 +175,33 @@ func (mr *MockDRPCSpaceSyncClientMockRecorder) SpacePush(ctx, in any) *gomock.Ca mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpacePush", reflect.TypeOf((*MockDRPCSpaceSyncClient)(nil).SpacePush), ctx, in) } + +// StoreDiff mocks base method. +func (m *MockDRPCSpaceSyncClient) StoreDiff(arg0 context.Context, arg1 *spacesyncproto.StoreDiffRequest) (*spacesyncproto.StoreDiffResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StoreDiff", arg0, arg1) + ret0, _ := ret[0].(*spacesyncproto.StoreDiffResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// StoreDiff indicates an expected call of StoreDiff. +func (mr *MockDRPCSpaceSyncClientMockRecorder) StoreDiff(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StoreDiff", reflect.TypeOf((*MockDRPCSpaceSyncClient)(nil).StoreDiff), arg0, arg1) +} + +// StoreElements mocks base method. +func (m *MockDRPCSpaceSyncClient) StoreElements(arg0 context.Context) (spacesyncproto.DRPCSpaceSync_StoreElementsClient, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StoreElements", arg0) + ret0, _ := ret[0].(spacesyncproto.DRPCSpaceSync_StoreElementsClient) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// StoreElements indicates an expected call of StoreElements. +func (mr *MockDRPCSpaceSyncClientMockRecorder) StoreElements(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StoreElements", reflect.TypeOf((*MockDRPCSpaceSyncClient)(nil).StoreElements), arg0) +} diff --git a/commonspace/spacesyncproto/protos/spacesync.proto b/commonspace/spacesyncproto/protos/spacesync.proto index a0d893d6..b14f76d6 100644 --- a/commonspace/spacesyncproto/protos/spacesync.proto +++ b/commonspace/spacesyncproto/protos/spacesync.proto @@ -20,6 +20,10 @@ enum ErrCodes { service SpaceSync { // HeadSync compares all objects and their hashes in a space rpc HeadSync(HeadSyncRequest) returns (HeadSyncResponse); + // StoreDiff compares all objects and their hashes in a space + rpc StoreDiff(StoreDiffRequest) returns (StoreDiffResponse); + // StoreElements exchanges elements between peers + rpc StoreElements(stream StoreKeyValue) returns (stream StoreKeyValue); // SpacePush sends new space to the node rpc SpacePush(SpacePushRequest) returns (SpacePushResponse); // SpacePull gets space from the remote peer @@ -79,6 +83,7 @@ message ObjectSyncMessage { string replyId = 3; bytes payload = 4; string objectId = 5; + ObjectType objectType = 6; } // SpacePushRequest is a request to add space on a node containing only one acl record @@ -144,6 +149,12 @@ message ObjectDelete { string id = 1; } +// StoreHeader is a header for a store +message StoreHeader { + string spaceId = 1; + string storageName = 2; +} + // SpaceDelete is a message containing deleter peer id message SpaceDelete { string deleterPeerId = 1; @@ -196,9 +207,51 @@ message AclGetRecordsResponse { repeated bytes records = 1; } +message StoreDiffRequest { + string spaceId = 1; + repeated HeadSyncRange ranges = 2; +} + +message StoreDiffResponse { + repeated HeadSyncResult results = 1; +} + +message StoreKeyValue { + string keyPeerId = 1; + bytes value = 2; + bytes identitySignature = 3; + bytes peerSignature = 4; + string spaceId = 5; +} + +message StoreKeyValues { + repeated StoreKeyValue keyValues = 1; +} + +message StoreKeyInner { + bytes peer = 1; + bytes identity = 2; + bytes value = 3; + int64 timestampMicro = 4; + string aclHeadId = 5; + string key = 6; +} + +message StorageHeader { + string spaceId = 1; + string storageName = 2; +} + // DiffType is a type of diff enum DiffType { Initial = 0; V1 = 1; V2 = 2; -} \ No newline at end of file +} + +// ObjectType is a type of object +enum ObjectType { + Tree = 0; + Acl = 1; + KeyValue = 2; +} diff --git a/commonspace/spacesyncproto/spacesync.pb.go b/commonspace/spacesyncproto/spacesync.pb.go index 20df01e7..eeb3d821 100644 --- a/commonspace/spacesyncproto/spacesync.pb.go +++ b/commonspace/spacesyncproto/spacesync.pb.go @@ -191,6 +191,56 @@ func (DiffType) EnumDescriptor() ([]byte, []int) { return file_commonspace_spacesyncproto_protos_spacesync_proto_rawDescGZIP(), []int{2} } +// ObjectType is a type of object +type ObjectType int32 + +const ( + ObjectType_Tree ObjectType = 0 + ObjectType_Acl ObjectType = 1 + ObjectType_KeyValue ObjectType = 2 +) + +// Enum value maps for ObjectType. +var ( + ObjectType_name = map[int32]string{ + 0: "Tree", + 1: "Acl", + 2: "KeyValue", + } + ObjectType_value = map[string]int32{ + "Tree": 0, + "Acl": 1, + "KeyValue": 2, + } +) + +func (x ObjectType) Enum() *ObjectType { + p := new(ObjectType) + *p = x + return p +} + +func (x ObjectType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ObjectType) Descriptor() protoreflect.EnumDescriptor { + return file_commonspace_spacesyncproto_protos_spacesync_proto_enumTypes[3].Descriptor() +} + +func (ObjectType) Type() protoreflect.EnumType { + return &file_commonspace_spacesyncproto_protos_spacesync_proto_enumTypes[3] +} + +func (x ObjectType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ObjectType.Descriptor instead. +func (ObjectType) EnumDescriptor() ([]byte, []int) { + return file_commonspace_spacesyncproto_protos_spacesync_proto_rawDescGZIP(), []int{3} +} + // HeadSyncRange presenting a request for one range type HeadSyncRange struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -496,6 +546,7 @@ type ObjectSyncMessage struct { ReplyId string `protobuf:"bytes,3,opt,name=replyId,proto3" json:"replyId,omitempty"` Payload []byte `protobuf:"bytes,4,opt,name=payload,proto3" json:"payload,omitempty"` ObjectId string `protobuf:"bytes,5,opt,name=objectId,proto3" json:"objectId,omitempty"` + ObjectType ObjectType `protobuf:"varint,6,opt,name=objectType,proto3,enum=spacesync.ObjectType" json:"objectType,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -565,6 +616,13 @@ func (x *ObjectSyncMessage) GetObjectId() string { return "" } +func (x *ObjectSyncMessage) GetObjectType() ObjectType { + if x != nil { + return x.ObjectType + } + return ObjectType_Tree +} + // SpacePushRequest is a request to add space on a node containing only one acl record type SpacePushRequest struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -1141,6 +1199,59 @@ func (x *ObjectDelete) GetId() string { return "" } +// StoreHeader is a header for a store +type StoreHeader struct { + state protoimpl.MessageState `protogen:"open.v1"` + SpaceId string `protobuf:"bytes,1,opt,name=spaceId,proto3" json:"spaceId,omitempty"` + StorageName string `protobuf:"bytes,2,opt,name=storageName,proto3" json:"storageName,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StoreHeader) Reset() { + *x = StoreHeader{} + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StoreHeader) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StoreHeader) ProtoMessage() {} + +func (x *StoreHeader) ProtoReflect() protoreflect.Message { + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[16] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StoreHeader.ProtoReflect.Descriptor instead. +func (*StoreHeader) Descriptor() ([]byte, []int) { + return file_commonspace_spacesyncproto_protos_spacesync_proto_rawDescGZIP(), []int{16} +} + +func (x *StoreHeader) GetSpaceId() string { + if x != nil { + return x.SpaceId + } + return "" +} + +func (x *StoreHeader) GetStorageName() string { + if x != nil { + return x.StorageName + } + return "" +} + // SpaceDelete is a message containing deleter peer id type SpaceDelete struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -1151,7 +1262,7 @@ type SpaceDelete struct { func (x *SpaceDelete) Reset() { *x = SpaceDelete{} - mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[16] + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1163,7 +1274,7 @@ func (x *SpaceDelete) String() string { func (*SpaceDelete) ProtoMessage() {} func (x *SpaceDelete) ProtoReflect() protoreflect.Message { - mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[16] + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1176,7 +1287,7 @@ func (x *SpaceDelete) ProtoReflect() protoreflect.Message { // Deprecated: Use SpaceDelete.ProtoReflect.Descriptor instead. func (*SpaceDelete) Descriptor() ([]byte, []int) { - return file_commonspace_spacesyncproto_protos_spacesync_proto_rawDescGZIP(), []int{16} + return file_commonspace_spacesyncproto_protos_spacesync_proto_rawDescGZIP(), []int{17} } func (x *SpaceDelete) GetDeleterPeerId() string { @@ -1197,7 +1308,7 @@ type SpaceSettingsSnapshot struct { func (x *SpaceSettingsSnapshot) Reset() { *x = SpaceSettingsSnapshot{} - mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[17] + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1209,7 +1320,7 @@ func (x *SpaceSettingsSnapshot) String() string { func (*SpaceSettingsSnapshot) ProtoMessage() {} func (x *SpaceSettingsSnapshot) ProtoReflect() protoreflect.Message { - mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[17] + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1222,7 +1333,7 @@ func (x *SpaceSettingsSnapshot) ProtoReflect() protoreflect.Message { // Deprecated: Use SpaceSettingsSnapshot.ProtoReflect.Descriptor instead. func (*SpaceSettingsSnapshot) Descriptor() ([]byte, []int) { - return file_commonspace_spacesyncproto_protos_spacesync_proto_rawDescGZIP(), []int{17} + return file_commonspace_spacesyncproto_protos_spacesync_proto_rawDescGZIP(), []int{18} } func (x *SpaceSettingsSnapshot) GetDeletedIds() []string { @@ -1250,7 +1361,7 @@ type SettingsData struct { func (x *SettingsData) Reset() { *x = SettingsData{} - mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[18] + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1262,7 +1373,7 @@ func (x *SettingsData) String() string { func (*SettingsData) ProtoMessage() {} func (x *SettingsData) ProtoReflect() protoreflect.Message { - mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[18] + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1275,7 +1386,7 @@ func (x *SettingsData) ProtoReflect() protoreflect.Message { // Deprecated: Use SettingsData.ProtoReflect.Descriptor instead. func (*SettingsData) Descriptor() ([]byte, []int) { - return file_commonspace_spacesyncproto_protos_spacesync_proto_rawDescGZIP(), []int{18} + return file_commonspace_spacesyncproto_protos_spacesync_proto_rawDescGZIP(), []int{19} } func (x *SettingsData) GetContent() []*SpaceSettingsContent { @@ -1302,7 +1413,7 @@ type SpaceSubscription struct { func (x *SpaceSubscription) Reset() { *x = SpaceSubscription{} - mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[19] + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1314,7 +1425,7 @@ func (x *SpaceSubscription) String() string { func (*SpaceSubscription) ProtoMessage() {} func (x *SpaceSubscription) ProtoReflect() protoreflect.Message { - mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[19] + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1327,7 +1438,7 @@ func (x *SpaceSubscription) ProtoReflect() protoreflect.Message { // Deprecated: Use SpaceSubscription.ProtoReflect.Descriptor instead. func (*SpaceSubscription) Descriptor() ([]byte, []int) { - return file_commonspace_spacesyncproto_protos_spacesync_proto_rawDescGZIP(), []int{19} + return file_commonspace_spacesyncproto_protos_spacesync_proto_rawDescGZIP(), []int{20} } func (x *SpaceSubscription) GetSpaceIds() []string { @@ -1355,7 +1466,7 @@ type AclAddRecordRequest struct { func (x *AclAddRecordRequest) Reset() { *x = AclAddRecordRequest{} - mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[20] + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1367,7 +1478,7 @@ func (x *AclAddRecordRequest) String() string { func (*AclAddRecordRequest) ProtoMessage() {} func (x *AclAddRecordRequest) ProtoReflect() protoreflect.Message { - mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[20] + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1380,7 +1491,7 @@ func (x *AclAddRecordRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AclAddRecordRequest.ProtoReflect.Descriptor instead. func (*AclAddRecordRequest) Descriptor() ([]byte, []int) { - return file_commonspace_spacesyncproto_protos_spacesync_proto_rawDescGZIP(), []int{20} + return file_commonspace_spacesyncproto_protos_spacesync_proto_rawDescGZIP(), []int{21} } func (x *AclAddRecordRequest) GetSpaceId() string { @@ -1408,7 +1519,7 @@ type AclAddRecordResponse struct { func (x *AclAddRecordResponse) Reset() { *x = AclAddRecordResponse{} - mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[21] + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1420,7 +1531,7 @@ func (x *AclAddRecordResponse) String() string { func (*AclAddRecordResponse) ProtoMessage() {} func (x *AclAddRecordResponse) ProtoReflect() protoreflect.Message { - mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[21] + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[22] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1433,7 +1544,7 @@ func (x *AclAddRecordResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AclAddRecordResponse.ProtoReflect.Descriptor instead. func (*AclAddRecordResponse) Descriptor() ([]byte, []int) { - return file_commonspace_spacesyncproto_protos_spacesync_proto_rawDescGZIP(), []int{21} + return file_commonspace_spacesyncproto_protos_spacesync_proto_rawDescGZIP(), []int{22} } func (x *AclAddRecordResponse) GetRecordId() string { @@ -1462,7 +1573,7 @@ type AclGetRecordsRequest struct { func (x *AclGetRecordsRequest) Reset() { *x = AclGetRecordsRequest{} - mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[22] + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1474,7 +1585,7 @@ func (x *AclGetRecordsRequest) String() string { func (*AclGetRecordsRequest) ProtoMessage() {} func (x *AclGetRecordsRequest) ProtoReflect() protoreflect.Message { - mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[22] + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[23] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1487,7 +1598,7 @@ func (x *AclGetRecordsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AclGetRecordsRequest.ProtoReflect.Descriptor instead. func (*AclGetRecordsRequest) Descriptor() ([]byte, []int) { - return file_commonspace_spacesyncproto_protos_spacesync_proto_rawDescGZIP(), []int{22} + return file_commonspace_spacesyncproto_protos_spacesync_proto_rawDescGZIP(), []int{23} } func (x *AclGetRecordsRequest) GetSpaceId() string { @@ -1514,7 +1625,7 @@ type AclGetRecordsResponse struct { func (x *AclGetRecordsResponse) Reset() { *x = AclGetRecordsResponse{} - mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[23] + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1526,7 +1637,7 @@ func (x *AclGetRecordsResponse) String() string { func (*AclGetRecordsResponse) ProtoMessage() {} func (x *AclGetRecordsResponse) ProtoReflect() protoreflect.Message { - mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[23] + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[24] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1539,7 +1650,7 @@ func (x *AclGetRecordsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AclGetRecordsResponse.ProtoReflect.Descriptor instead. func (*AclGetRecordsResponse) Descriptor() ([]byte, []int) { - return file_commonspace_spacesyncproto_protos_spacesync_proto_rawDescGZIP(), []int{23} + return file_commonspace_spacesyncproto_protos_spacesync_proto_rawDescGZIP(), []int{24} } func (x *AclGetRecordsResponse) GetRecords() [][]byte { @@ -1549,6 +1660,358 @@ func (x *AclGetRecordsResponse) GetRecords() [][]byte { return nil } +type StoreDiffRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + SpaceId string `protobuf:"bytes,1,opt,name=spaceId,proto3" json:"spaceId,omitempty"` + Ranges []*HeadSyncRange `protobuf:"bytes,2,rep,name=ranges,proto3" json:"ranges,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StoreDiffRequest) Reset() { + *x = StoreDiffRequest{} + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StoreDiffRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StoreDiffRequest) ProtoMessage() {} + +func (x *StoreDiffRequest) ProtoReflect() protoreflect.Message { + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[25] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StoreDiffRequest.ProtoReflect.Descriptor instead. +func (*StoreDiffRequest) Descriptor() ([]byte, []int) { + return file_commonspace_spacesyncproto_protos_spacesync_proto_rawDescGZIP(), []int{25} +} + +func (x *StoreDiffRequest) GetSpaceId() string { + if x != nil { + return x.SpaceId + } + return "" +} + +func (x *StoreDiffRequest) GetRanges() []*HeadSyncRange { + if x != nil { + return x.Ranges + } + return nil +} + +type StoreDiffResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Results []*HeadSyncResult `protobuf:"bytes,1,rep,name=results,proto3" json:"results,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StoreDiffResponse) Reset() { + *x = StoreDiffResponse{} + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StoreDiffResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StoreDiffResponse) ProtoMessage() {} + +func (x *StoreDiffResponse) ProtoReflect() protoreflect.Message { + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[26] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StoreDiffResponse.ProtoReflect.Descriptor instead. +func (*StoreDiffResponse) Descriptor() ([]byte, []int) { + return file_commonspace_spacesyncproto_protos_spacesync_proto_rawDescGZIP(), []int{26} +} + +func (x *StoreDiffResponse) GetResults() []*HeadSyncResult { + if x != nil { + return x.Results + } + return nil +} + +type StoreKeyValue struct { + state protoimpl.MessageState `protogen:"open.v1"` + KeyPeerId string `protobuf:"bytes,1,opt,name=keyPeerId,proto3" json:"keyPeerId,omitempty"` + Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` + IdentitySignature []byte `protobuf:"bytes,3,opt,name=identitySignature,proto3" json:"identitySignature,omitempty"` + PeerSignature []byte `protobuf:"bytes,4,opt,name=peerSignature,proto3" json:"peerSignature,omitempty"` + SpaceId string `protobuf:"bytes,5,opt,name=spaceId,proto3" json:"spaceId,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StoreKeyValue) Reset() { + *x = StoreKeyValue{} + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StoreKeyValue) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StoreKeyValue) ProtoMessage() {} + +func (x *StoreKeyValue) ProtoReflect() protoreflect.Message { + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[27] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StoreKeyValue.ProtoReflect.Descriptor instead. +func (*StoreKeyValue) Descriptor() ([]byte, []int) { + return file_commonspace_spacesyncproto_protos_spacesync_proto_rawDescGZIP(), []int{27} +} + +func (x *StoreKeyValue) GetKeyPeerId() string { + if x != nil { + return x.KeyPeerId + } + return "" +} + +func (x *StoreKeyValue) GetValue() []byte { + if x != nil { + return x.Value + } + return nil +} + +func (x *StoreKeyValue) GetIdentitySignature() []byte { + if x != nil { + return x.IdentitySignature + } + return nil +} + +func (x *StoreKeyValue) GetPeerSignature() []byte { + if x != nil { + return x.PeerSignature + } + return nil +} + +func (x *StoreKeyValue) GetSpaceId() string { + if x != nil { + return x.SpaceId + } + return "" +} + +type StoreKeyValues struct { + state protoimpl.MessageState `protogen:"open.v1"` + KeyValues []*StoreKeyValue `protobuf:"bytes,1,rep,name=keyValues,proto3" json:"keyValues,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StoreKeyValues) Reset() { + *x = StoreKeyValues{} + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StoreKeyValues) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StoreKeyValues) ProtoMessage() {} + +func (x *StoreKeyValues) ProtoReflect() protoreflect.Message { + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[28] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StoreKeyValues.ProtoReflect.Descriptor instead. +func (*StoreKeyValues) Descriptor() ([]byte, []int) { + return file_commonspace_spacesyncproto_protos_spacesync_proto_rawDescGZIP(), []int{28} +} + +func (x *StoreKeyValues) GetKeyValues() []*StoreKeyValue { + if x != nil { + return x.KeyValues + } + return nil +} + +type StoreKeyInner struct { + state protoimpl.MessageState `protogen:"open.v1"` + Peer []byte `protobuf:"bytes,1,opt,name=peer,proto3" json:"peer,omitempty"` + Identity []byte `protobuf:"bytes,2,opt,name=identity,proto3" json:"identity,omitempty"` + Value []byte `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` + TimestampMicro int64 `protobuf:"varint,4,opt,name=timestampMicro,proto3" json:"timestampMicro,omitempty"` + AclHeadId string `protobuf:"bytes,5,opt,name=aclHeadId,proto3" json:"aclHeadId,omitempty"` + Key string `protobuf:"bytes,6,opt,name=key,proto3" json:"key,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StoreKeyInner) Reset() { + *x = StoreKeyInner{} + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StoreKeyInner) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StoreKeyInner) ProtoMessage() {} + +func (x *StoreKeyInner) ProtoReflect() protoreflect.Message { + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[29] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StoreKeyInner.ProtoReflect.Descriptor instead. +func (*StoreKeyInner) Descriptor() ([]byte, []int) { + return file_commonspace_spacesyncproto_protos_spacesync_proto_rawDescGZIP(), []int{29} +} + +func (x *StoreKeyInner) GetPeer() []byte { + if x != nil { + return x.Peer + } + return nil +} + +func (x *StoreKeyInner) GetIdentity() []byte { + if x != nil { + return x.Identity + } + return nil +} + +func (x *StoreKeyInner) GetValue() []byte { + if x != nil { + return x.Value + } + return nil +} + +func (x *StoreKeyInner) GetTimestampMicro() int64 { + if x != nil { + return x.TimestampMicro + } + return 0 +} + +func (x *StoreKeyInner) GetAclHeadId() string { + if x != nil { + return x.AclHeadId + } + return "" +} + +func (x *StoreKeyInner) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +type StorageHeader struct { + state protoimpl.MessageState `protogen:"open.v1"` + SpaceId string `protobuf:"bytes,1,opt,name=spaceId,proto3" json:"spaceId,omitempty"` + StorageName string `protobuf:"bytes,2,opt,name=storageName,proto3" json:"storageName,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StorageHeader) Reset() { + *x = StorageHeader{} + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StorageHeader) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StorageHeader) ProtoMessage() {} + +func (x *StorageHeader) ProtoReflect() protoreflect.Message { + mi := &file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes[30] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StorageHeader.ProtoReflect.Descriptor instead. +func (*StorageHeader) Descriptor() ([]byte, []int) { + return file_commonspace_spacesyncproto_protos_spacesync_proto_rawDescGZIP(), []int{30} +} + +func (x *StorageHeader) GetSpaceId() string { + if x != nil { + return x.SpaceId + } + return "" +} + +func (x *StorageHeader) GetStorageName() string { + if x != nil { + return x.StorageName + } + return "" +} + var File_commonspace_spacesyncproto_protos_spacesync_proto protoreflect.FileDescriptor var file_commonspace_spacesyncproto_protos_spacesync_proto_rawDesc = string([]byte{ @@ -1590,7 +2053,7 @@ var file_commonspace_spacesyncproto_protos_spacesync_proto_rawDesc = string([]by 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x2f, 0x0a, 0x08, 0x64, 0x69, 0x66, 0x66, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x13, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x44, 0x69, 0x66, 0x66, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x64, - 0x69, 0x66, 0x66, 0x54, 0x79, 0x70, 0x65, 0x22, 0x9b, 0x01, 0x0a, 0x11, 0x4f, 0x62, 0x6a, 0x65, + 0x69, 0x66, 0x66, 0x54, 0x79, 0x70, 0x65, 0x22, 0xd2, 0x01, 0x0a, 0x11, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, @@ -1600,178 +2063,240 @@ var file_commonspace_spacesyncproto_protos_spacesync_proto_rawDesc = string([]by 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6f, 0x62, 0x6a, - 0x65, 0x63, 0x74, 0x49, 0x64, 0x22, 0x65, 0x0a, 0x10, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x75, - 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x07, 0x70, 0x61, 0x79, - 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x79, 0x6c, - 0x6f, 0x61, 0x64, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x1e, 0x0a, 0x0a, - 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x0a, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0x13, 0x0a, 0x11, - 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x22, 0x0a, 0x10, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x75, 0x6c, 0x6c, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x46, 0x0a, 0x11, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x75, - 0x6c, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, 0x07, 0x70, 0x61, - 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x79, - 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x81, 0x02, - 0x0a, 0x0c, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x41, + 0x65, 0x63, 0x74, 0x49, 0x64, 0x12, 0x35, 0x0a, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, + 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, + 0x52, 0x0a, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0x65, 0x0a, 0x10, + 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x31, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x53, 0x70, + 0x61, 0x63, 0x65, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, + 0x6f, 0x61, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, + 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x61, 0x6c, 0x22, 0x13, 0x0a, 0x11, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x75, 0x73, 0x68, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x0a, 0x10, 0x53, 0x70, 0x61, 0x63, + 0x65, 0x50, 0x75, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x46, 0x0a, 0x11, + 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x75, 0x6c, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x31, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x53, + 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x07, 0x70, 0x61, 0x79, + 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x81, 0x02, 0x0a, 0x0c, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, + 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x41, 0x0a, 0x0b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x48, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x52, 0x61, 0x77, 0x53, 0x70, 0x61, 0x63, 0x65, 0x48, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x57, 0x69, 0x74, 0x68, 0x49, 0x64, 0x52, 0x0b, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x63, 0x6c, 0x50, + 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x61, 0x63, + 0x6c, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x63, 0x6c, 0x50, + 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, + 0x61, 0x63, 0x6c, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x14, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x50, 0x61, 0x79, + 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x14, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, + 0x12, 0x36, 0x0a, 0x16, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, + 0x73, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x16, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x50, + 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x22, 0xd1, 0x01, 0x0a, 0x0b, 0x53, 0x70, 0x61, + 0x63, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x69, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4b, + 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x65, 0x65, 0x64, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x73, 0x65, 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x12, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6c, 0x6f, + 0x61, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x12, 0x73, 0x70, 0x61, 0x63, 0x65, 0x48, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x50, 0x0a, 0x0e, + 0x52, 0x61, 0x77, 0x53, 0x70, 0x61, 0x63, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, - 0x52, 0x61, 0x77, 0x53, 0x70, 0x61, 0x63, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x57, 0x69, - 0x74, 0x68, 0x49, 0x64, 0x52, 0x0b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, - 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x63, 0x6c, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x61, 0x63, 0x6c, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, - 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x63, 0x6c, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x49, - 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x63, 0x6c, 0x50, 0x61, 0x79, 0x6c, - 0x6f, 0x61, 0x64, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x14, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, - 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x14, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, - 0x67, 0x73, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x36, 0x0a, 0x16, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, - 0x64, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x49, - 0x64, 0x22, 0xd1, 0x01, 0x0a, 0x0b, 0x53, 0x70, 0x61, 0x63, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, - 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x1c, 0x0a, - 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1c, 0x0a, 0x09, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x65, 0x70, - 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x0e, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, - 0x79, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x65, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x04, 0x73, 0x65, 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x12, 0x73, 0x70, 0x61, 0x63, 0x65, 0x48, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x12, 0x73, 0x70, 0x61, 0x63, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x50, 0x61, - 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x50, 0x0a, 0x0e, 0x52, 0x61, 0x77, 0x53, 0x70, 0x61, 0x63, - 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x44, 0x0a, 0x14, 0x52, 0x61, 0x77, 0x53, 0x70, - 0x61, 0x63, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x57, 0x69, 0x74, 0x68, 0x49, 0x64, 0x12, - 0x1c, 0x0a, 0x09, 0x72, 0x61, 0x77, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x09, 0x72, 0x61, 0x77, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x0e, 0x0a, - 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x9a, 0x01, - 0x0a, 0x14, 0x53, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x43, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x3d, 0x0a, 0x0c, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x0c, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x3a, 0x0a, 0x0b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x53, 0x70, 0x61, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x1e, 0x0a, 0x0c, 0x4f, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x33, 0x0a, 0x0b, 0x53, 0x70, - 0x61, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x64, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x72, 0x50, 0x65, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0d, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x50, 0x65, 0x65, 0x72, 0x49, 0x64, 0x22, - 0x5d, 0x0a, 0x15, 0x53, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, - 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x64, 0x49, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x64, 0x49, 0x64, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x64, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x72, 0x50, 0x65, 0x65, 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0d, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x50, 0x65, 0x65, 0x72, 0x49, 0x64, 0x22, 0x87, - 0x01, 0x0a, 0x0c, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x44, 0x61, 0x74, 0x61, 0x12, - 0x39, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x1f, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x53, 0x70, 0x61, - 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x3c, 0x0a, 0x08, 0x73, 0x6e, - 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x53, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, - 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x08, - 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x22, 0x6b, 0x0a, 0x11, 0x53, 0x70, 0x61, 0x63, - 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, - 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x53, 0x70, 0x61, 0x63, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x49, 0x0a, 0x13, 0x41, 0x63, 0x6c, 0x41, 0x64, 0x64, 0x52, - 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, + 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x44, + 0x0a, 0x14, 0x52, 0x61, 0x77, 0x53, 0x70, 0x61, 0x63, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x57, 0x69, 0x74, 0x68, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x61, 0x77, 0x48, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x72, 0x61, 0x77, 0x48, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x02, 0x69, 0x64, 0x22, 0x9a, 0x01, 0x0a, 0x14, 0x53, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, + 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x3d, 0x0a, + 0x0c, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, + 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x0c, + 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x3a, 0x0a, 0x0b, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x16, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x53, 0x70, + 0x61, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x22, 0x1e, 0x0a, 0x0c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, + 0x64, 0x22, 0x49, 0x0a, 0x0b, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x12, 0x18, 0x0a, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x33, 0x0a, 0x0b, + 0x53, 0x70, 0x61, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x64, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x50, 0x65, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0d, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x50, 0x65, 0x65, 0x72, 0x49, + 0x64, 0x22, 0x5d, 0x0a, 0x15, 0x53, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x73, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x64, 0x49, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, + 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x49, 0x64, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x64, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x72, 0x50, 0x65, 0x65, 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0d, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x50, 0x65, 0x65, 0x72, 0x49, 0x64, + 0x22, 0x87, 0x01, 0x0a, 0x0c, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x44, 0x61, 0x74, + 0x61, 0x12, 0x39, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x53, + 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x43, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x3c, 0x0a, 0x08, + 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, + 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x53, 0x70, 0x61, 0x63, 0x65, + 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, + 0x52, 0x08, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x22, 0x6b, 0x0a, 0x11, 0x53, 0x70, + 0x61, 0x63, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x1a, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x53, 0x70, 0x61, 0x63, 0x65, 0x53, 0x75, 0x62, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x49, 0x0a, 0x13, 0x41, 0x63, 0x6c, 0x41, 0x64, + 0x64, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, + 0x0a, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, + 0x6f, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, + 0x61, 0x64, 0x22, 0x4c, 0x0a, 0x14, 0x41, 0x63, 0x6c, 0x41, 0x64, 0x64, 0x52, 0x65, 0x63, 0x6f, + 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, + 0x63, 0x6f, 0x72, 0x64, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, + 0x63, 0x6f, 0x72, 0x64, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, - 0x22, 0x4c, 0x0a, 0x14, 0x41, 0x63, 0x6c, 0x41, 0x64, 0x64, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x63, 0x6f, - 0x72, 0x64, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x63, 0x6f, - 0x72, 0x64, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x4a, - 0x0a, 0x14, 0x41, 0x63, 0x6c, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, - 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63, 0x6c, 0x48, 0x65, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x61, 0x63, 0x6c, 0x48, 0x65, 0x61, 0x64, 0x22, 0x31, 0x0a, 0x15, 0x41, 0x63, - 0x6c, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0c, 0x52, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x2a, 0xee, 0x01, - 0x0a, 0x08, 0x45, 0x72, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x0e, 0x0a, 0x0a, 0x55, 0x6e, - 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x70, - 0x61, 0x63, 0x65, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, - 0x53, 0x70, 0x61, 0x63, 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x10, 0x02, 0x12, 0x13, 0x0a, - 0x0f, 0x53, 0x70, 0x61, 0x63, 0x65, 0x4e, 0x6f, 0x74, 0x49, 0x6e, 0x43, 0x61, 0x63, 0x68, 0x65, - 0x10, 0x03, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x70, 0x61, 0x63, 0x65, 0x49, 0x73, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x64, 0x10, 0x04, 0x12, 0x18, 0x0a, 0x14, 0x50, 0x65, 0x65, 0x72, 0x49, 0x73, - 0x4e, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x10, 0x05, - 0x12, 0x14, 0x0a, 0x10, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x49, 0x73, 0x49, 0x6e, 0x76, - 0x61, 0x6c, 0x69, 0x64, 0x10, 0x06, 0x12, 0x12, 0x0a, 0x0e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, - 0x64, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x10, 0x07, 0x12, 0x14, 0x0a, 0x10, 0x44, 0x75, - 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0x08, - 0x12, 0x1b, 0x0a, 0x17, 0x54, 0x6f, 0x6f, 0x4d, 0x61, 0x6e, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x73, 0x46, 0x72, 0x6f, 0x6d, 0x50, 0x65, 0x65, 0x72, 0x10, 0x09, 0x12, 0x0f, 0x0a, - 0x0b, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x10, 0x64, 0x2a, 0x39, - 0x0a, 0x17, 0x53, 0x70, 0x61, 0x63, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x75, 0x62, - 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x6e, 0x73, 0x75, - 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x10, 0x01, 0x2a, 0x27, 0x0a, 0x08, 0x44, 0x69, 0x66, - 0x66, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, - 0x10, 0x00, 0x12, 0x06, 0x0a, 0x02, 0x56, 0x31, 0x10, 0x01, 0x12, 0x06, 0x0a, 0x02, 0x56, 0x32, - 0x10, 0x02, 0x32, 0xfc, 0x04, 0x0a, 0x09, 0x53, 0x70, 0x61, 0x63, 0x65, 0x53, 0x79, 0x6e, 0x63, - 0x12, 0x43, 0x0a, 0x08, 0x48, 0x65, 0x61, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x1a, 0x2e, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x53, 0x79, 0x6e, - 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x09, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x75, - 0x73, 0x68, 0x12, 0x1b, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x53, - 0x70, 0x61, 0x63, 0x65, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1c, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x53, 0x70, 0x61, 0x63, - 0x65, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, - 0x09, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x75, 0x6c, 0x6c, 0x12, 0x1b, 0x2e, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x75, 0x6c, 0x6c, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, - 0x79, 0x6e, 0x63, 0x2e, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x75, 0x6c, 0x6c, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, 0x10, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, - 0x79, 0x6e, 0x63, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1c, 0x2e, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x79, 0x6e, 0x63, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1c, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, - 0x79, 0x6e, 0x63, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x48, 0x0a, 0x0a, 0x4f, 0x62, 0x6a, - 0x65, 0x63, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x1c, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, - 0x79, 0x6e, 0x63, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1c, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, - 0x63, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x57, 0x0a, 0x17, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x79, 0x6e, - 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1c, + 0x22, 0x4a, 0x0a, 0x14, 0x41, 0x63, 0x6c, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63, 0x6c, 0x48, 0x65, 0x61, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x6c, 0x48, 0x65, 0x61, 0x64, 0x22, 0x31, 0x0a, 0x15, + 0x41, 0x63, 0x6c, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x22, + 0x5e, 0x0a, 0x10, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x44, 0x69, 0x66, 0x66, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x30, 0x0a, + 0x06, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x53, 0x79, + 0x6e, 0x63, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x06, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x22, + 0x48, 0x0a, 0x11, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x44, 0x69, 0x66, 0x66, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, + 0x63, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x22, 0xb1, 0x01, 0x0a, 0x0d, 0x53, 0x74, + 0x6f, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6b, + 0x65, 0x79, 0x50, 0x65, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x6b, 0x65, 0x79, 0x50, 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, + 0x2c, 0x0a, 0x11, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x11, 0x69, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x24, 0x0a, + 0x0d, 0x70, 0x65, 0x65, 0x72, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x70, 0x65, 0x65, 0x72, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x22, 0x48, 0x0a, + 0x0e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, + 0x36, 0x0a, 0x09, 0x6b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x53, + 0x74, 0x6f, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x09, 0x6b, 0x65, + 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0xad, 0x01, 0x0a, 0x0d, 0x53, 0x74, 0x6f, 0x72, + 0x65, 0x4b, 0x65, 0x79, 0x49, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x65, 0x65, + 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x70, 0x65, 0x65, 0x72, 0x12, 0x1a, 0x0a, + 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, + 0x26, 0x0a, 0x0e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4d, 0x69, 0x63, 0x72, + 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x63, 0x6c, 0x48, 0x65, + 0x61, 0x64, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x6c, 0x48, + 0x65, 0x61, 0x64, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x4b, 0x0a, 0x0d, 0x53, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, + 0x4e, 0x61, 0x6d, 0x65, 0x2a, 0xee, 0x01, 0x0a, 0x08, 0x45, 0x72, 0x72, 0x43, 0x6f, 0x64, 0x65, + 0x73, 0x12, 0x0e, 0x0a, 0x0a, 0x55, 0x6e, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x10, + 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x70, 0x61, 0x63, 0x65, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, + 0x67, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x70, 0x61, 0x63, 0x65, 0x45, 0x78, 0x69, 0x73, + 0x74, 0x73, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x70, 0x61, 0x63, 0x65, 0x4e, 0x6f, 0x74, + 0x49, 0x6e, 0x43, 0x61, 0x63, 0x68, 0x65, 0x10, 0x03, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x70, 0x61, + 0x63, 0x65, 0x49, 0x73, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x10, 0x04, 0x12, 0x18, 0x0a, + 0x14, 0x50, 0x65, 0x65, 0x72, 0x49, 0x73, 0x4e, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x69, 0x62, 0x6c, 0x65, 0x10, 0x05, 0x12, 0x14, 0x0a, 0x10, 0x52, 0x65, 0x63, 0x65, 0x69, + 0x70, 0x74, 0x49, 0x73, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x10, 0x06, 0x12, 0x12, 0x0a, + 0x0e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x10, + 0x07, 0x12, 0x14, 0x0a, 0x10, 0x44, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0x08, 0x12, 0x1b, 0x0a, 0x17, 0x54, 0x6f, 0x6f, 0x4d, 0x61, + 0x6e, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x46, 0x72, 0x6f, 0x6d, 0x50, 0x65, + 0x65, 0x72, 0x10, 0x09, 0x12, 0x0f, 0x0a, 0x0b, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x4f, 0x66, 0x66, + 0x73, 0x65, 0x74, 0x10, 0x64, 0x2a, 0x39, 0x0a, 0x17, 0x53, 0x70, 0x61, 0x63, 0x65, 0x53, 0x75, + 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x10, 0x00, 0x12, + 0x0f, 0x0a, 0x0b, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x10, 0x01, + 0x2a, 0x27, 0x0a, 0x08, 0x44, 0x69, 0x66, 0x66, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, + 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x10, 0x00, 0x12, 0x06, 0x0a, 0x02, 0x56, 0x31, 0x10, + 0x01, 0x12, 0x06, 0x0a, 0x02, 0x56, 0x32, 0x10, 0x02, 0x2a, 0x2d, 0x0a, 0x0a, 0x4f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x54, 0x72, 0x65, 0x65, 0x10, + 0x00, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x63, 0x6c, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x4b, 0x65, + 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x10, 0x02, 0x32, 0x8d, 0x06, 0x0a, 0x09, 0x53, 0x70, 0x61, + 0x63, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x43, 0x0a, 0x08, 0x48, 0x65, 0x61, 0x64, 0x53, 0x79, + 0x6e, 0x63, 0x12, 0x1a, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x48, + 0x65, 0x61, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, + 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x53, + 0x79, 0x6e, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x09, 0x53, + 0x74, 0x6f, 0x72, 0x65, 0x44, 0x69, 0x66, 0x66, 0x12, 0x1b, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x44, 0x69, 0x66, 0x66, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, + 0x63, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x44, 0x69, 0x66, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0d, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x45, 0x6c, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x73, 0x12, 0x18, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, + 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x18, + 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, + 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x46, 0x0a, 0x09, + 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x75, 0x73, 0x68, 0x12, 0x1b, 0x2e, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x75, 0x73, 0x68, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, + 0x6e, 0x63, 0x2e, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x09, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x75, 0x6c, + 0x6c, 0x12, 0x1b, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x53, 0x70, + 0x61, 0x63, 0x65, 0x50, 0x75, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, + 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x53, 0x70, 0x61, 0x63, 0x65, + 0x50, 0x75, 0x6c, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, 0x10, + 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x12, 0x1c, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x4f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1c, + 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x28, 0x01, 0x30, 0x01, + 0x12, 0x48, 0x0a, 0x0a, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x1c, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1c, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, - 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x30, 0x01, 0x12, 0x4f, 0x0a, 0x0c, - 0x41, 0x63, 0x6c, 0x41, 0x64, 0x64, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x1e, 0x2e, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x41, 0x63, 0x6c, 0x41, 0x64, 0x64, 0x52, - 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x41, 0x63, 0x6c, 0x41, 0x64, 0x64, 0x52, - 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, - 0x0d, 0x41, 0x63, 0x6c, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x1f, - 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x41, 0x63, 0x6c, 0x47, 0x65, - 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x20, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, 0x41, 0x63, 0x6c, 0x47, - 0x65, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x42, 0x1c, 0x5a, 0x1a, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x2f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x57, 0x0a, 0x17, 0x4f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1c, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, + 0x63, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x1a, 0x1c, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, + 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x30, 0x01, 0x12, 0x4f, 0x0a, 0x0c, 0x41, 0x63, 0x6c, 0x41, 0x64, 0x64, 0x52, 0x65, 0x63, + 0x6f, 0x72, 0x64, 0x12, 0x1e, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, + 0x41, 0x63, 0x6c, 0x41, 0x64, 0x64, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x2e, + 0x41, 0x63, 0x6c, 0x41, 0x64, 0x64, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, 0x0d, 0x41, 0x63, 0x6c, 0x47, 0x65, 0x74, 0x52, 0x65, + 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x1f, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, + 0x63, 0x2e, 0x41, 0x63, 0x6c, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, + 0x6e, 0x63, 0x2e, 0x41, 0x63, 0x6c, 0x47, 0x65, 0x74, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x1c, 0x5a, 0x1a, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x79, 0x6e, + 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, }) var ( @@ -1786,72 +2311,88 @@ func file_commonspace_spacesyncproto_protos_spacesync_proto_rawDescGZIP() []byte return file_commonspace_spacesyncproto_protos_spacesync_proto_rawDescData } -var file_commonspace_spacesyncproto_protos_spacesync_proto_enumTypes = make([]protoimpl.EnumInfo, 3) -var file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes = make([]protoimpl.MessageInfo, 24) +var file_commonspace_spacesyncproto_protos_spacesync_proto_enumTypes = make([]protoimpl.EnumInfo, 4) +var file_commonspace_spacesyncproto_protos_spacesync_proto_msgTypes = make([]protoimpl.MessageInfo, 31) var file_commonspace_spacesyncproto_protos_spacesync_proto_goTypes = []any{ (ErrCodes)(0), // 0: spacesync.ErrCodes (SpaceSubscriptionAction)(0), // 1: spacesync.SpaceSubscriptionAction (DiffType)(0), // 2: spacesync.DiffType - (*HeadSyncRange)(nil), // 3: spacesync.HeadSyncRange - (*HeadSyncResult)(nil), // 4: spacesync.HeadSyncResult - (*HeadSyncResultElement)(nil), // 5: spacesync.HeadSyncResultElement - (*HeadSyncRequest)(nil), // 6: spacesync.HeadSyncRequest - (*HeadSyncResponse)(nil), // 7: spacesync.HeadSyncResponse - (*ObjectSyncMessage)(nil), // 8: spacesync.ObjectSyncMessage - (*SpacePushRequest)(nil), // 9: spacesync.SpacePushRequest - (*SpacePushResponse)(nil), // 10: spacesync.SpacePushResponse - (*SpacePullRequest)(nil), // 11: spacesync.SpacePullRequest - (*SpacePullResponse)(nil), // 12: spacesync.SpacePullResponse - (*SpacePayload)(nil), // 13: spacesync.SpacePayload - (*SpaceHeader)(nil), // 14: spacesync.SpaceHeader - (*RawSpaceHeader)(nil), // 15: spacesync.RawSpaceHeader - (*RawSpaceHeaderWithId)(nil), // 16: spacesync.RawSpaceHeaderWithId - (*SpaceSettingsContent)(nil), // 17: spacesync.SpaceSettingsContent - (*ObjectDelete)(nil), // 18: spacesync.ObjectDelete - (*SpaceDelete)(nil), // 19: spacesync.SpaceDelete - (*SpaceSettingsSnapshot)(nil), // 20: spacesync.SpaceSettingsSnapshot - (*SettingsData)(nil), // 21: spacesync.SettingsData - (*SpaceSubscription)(nil), // 22: spacesync.SpaceSubscription - (*AclAddRecordRequest)(nil), // 23: spacesync.AclAddRecordRequest - (*AclAddRecordResponse)(nil), // 24: spacesync.AclAddRecordResponse - (*AclGetRecordsRequest)(nil), // 25: spacesync.AclGetRecordsRequest - (*AclGetRecordsResponse)(nil), // 26: spacesync.AclGetRecordsResponse + (ObjectType)(0), // 3: spacesync.ObjectType + (*HeadSyncRange)(nil), // 4: spacesync.HeadSyncRange + (*HeadSyncResult)(nil), // 5: spacesync.HeadSyncResult + (*HeadSyncResultElement)(nil), // 6: spacesync.HeadSyncResultElement + (*HeadSyncRequest)(nil), // 7: spacesync.HeadSyncRequest + (*HeadSyncResponse)(nil), // 8: spacesync.HeadSyncResponse + (*ObjectSyncMessage)(nil), // 9: spacesync.ObjectSyncMessage + (*SpacePushRequest)(nil), // 10: spacesync.SpacePushRequest + (*SpacePushResponse)(nil), // 11: spacesync.SpacePushResponse + (*SpacePullRequest)(nil), // 12: spacesync.SpacePullRequest + (*SpacePullResponse)(nil), // 13: spacesync.SpacePullResponse + (*SpacePayload)(nil), // 14: spacesync.SpacePayload + (*SpaceHeader)(nil), // 15: spacesync.SpaceHeader + (*RawSpaceHeader)(nil), // 16: spacesync.RawSpaceHeader + (*RawSpaceHeaderWithId)(nil), // 17: spacesync.RawSpaceHeaderWithId + (*SpaceSettingsContent)(nil), // 18: spacesync.SpaceSettingsContent + (*ObjectDelete)(nil), // 19: spacesync.ObjectDelete + (*StoreHeader)(nil), // 20: spacesync.StoreHeader + (*SpaceDelete)(nil), // 21: spacesync.SpaceDelete + (*SpaceSettingsSnapshot)(nil), // 22: spacesync.SpaceSettingsSnapshot + (*SettingsData)(nil), // 23: spacesync.SettingsData + (*SpaceSubscription)(nil), // 24: spacesync.SpaceSubscription + (*AclAddRecordRequest)(nil), // 25: spacesync.AclAddRecordRequest + (*AclAddRecordResponse)(nil), // 26: spacesync.AclAddRecordResponse + (*AclGetRecordsRequest)(nil), // 27: spacesync.AclGetRecordsRequest + (*AclGetRecordsResponse)(nil), // 28: spacesync.AclGetRecordsResponse + (*StoreDiffRequest)(nil), // 29: spacesync.StoreDiffRequest + (*StoreDiffResponse)(nil), // 30: spacesync.StoreDiffResponse + (*StoreKeyValue)(nil), // 31: spacesync.StoreKeyValue + (*StoreKeyValues)(nil), // 32: spacesync.StoreKeyValues + (*StoreKeyInner)(nil), // 33: spacesync.StoreKeyInner + (*StorageHeader)(nil), // 34: spacesync.StorageHeader } var file_commonspace_spacesyncproto_protos_spacesync_proto_depIdxs = []int32{ - 5, // 0: spacesync.HeadSyncResult.elements:type_name -> spacesync.HeadSyncResultElement - 3, // 1: spacesync.HeadSyncRequest.ranges:type_name -> spacesync.HeadSyncRange + 6, // 0: spacesync.HeadSyncResult.elements:type_name -> spacesync.HeadSyncResultElement + 4, // 1: spacesync.HeadSyncRequest.ranges:type_name -> spacesync.HeadSyncRange 2, // 2: spacesync.HeadSyncRequest.diffType:type_name -> spacesync.DiffType - 4, // 3: spacesync.HeadSyncResponse.results:type_name -> spacesync.HeadSyncResult + 5, // 3: spacesync.HeadSyncResponse.results:type_name -> spacesync.HeadSyncResult 2, // 4: spacesync.HeadSyncResponse.diffType:type_name -> spacesync.DiffType - 13, // 5: spacesync.SpacePushRequest.payload:type_name -> spacesync.SpacePayload - 13, // 6: spacesync.SpacePullResponse.payload:type_name -> spacesync.SpacePayload - 16, // 7: spacesync.SpacePayload.spaceHeader:type_name -> spacesync.RawSpaceHeaderWithId - 18, // 8: spacesync.SpaceSettingsContent.objectDelete:type_name -> spacesync.ObjectDelete - 19, // 9: spacesync.SpaceSettingsContent.spaceDelete:type_name -> spacesync.SpaceDelete - 17, // 10: spacesync.SettingsData.content:type_name -> spacesync.SpaceSettingsContent - 20, // 11: spacesync.SettingsData.snapshot:type_name -> spacesync.SpaceSettingsSnapshot - 1, // 12: spacesync.SpaceSubscription.action:type_name -> spacesync.SpaceSubscriptionAction - 6, // 13: spacesync.SpaceSync.HeadSync:input_type -> spacesync.HeadSyncRequest - 9, // 14: spacesync.SpaceSync.SpacePush:input_type -> spacesync.SpacePushRequest - 11, // 15: spacesync.SpaceSync.SpacePull:input_type -> spacesync.SpacePullRequest - 8, // 16: spacesync.SpaceSync.ObjectSyncStream:input_type -> spacesync.ObjectSyncMessage - 8, // 17: spacesync.SpaceSync.ObjectSync:input_type -> spacesync.ObjectSyncMessage - 8, // 18: spacesync.SpaceSync.ObjectSyncRequestStream:input_type -> spacesync.ObjectSyncMessage - 23, // 19: spacesync.SpaceSync.AclAddRecord:input_type -> spacesync.AclAddRecordRequest - 25, // 20: spacesync.SpaceSync.AclGetRecords:input_type -> spacesync.AclGetRecordsRequest - 7, // 21: spacesync.SpaceSync.HeadSync:output_type -> spacesync.HeadSyncResponse - 10, // 22: spacesync.SpaceSync.SpacePush:output_type -> spacesync.SpacePushResponse - 12, // 23: spacesync.SpaceSync.SpacePull:output_type -> spacesync.SpacePullResponse - 8, // 24: spacesync.SpaceSync.ObjectSyncStream:output_type -> spacesync.ObjectSyncMessage - 8, // 25: spacesync.SpaceSync.ObjectSync:output_type -> spacesync.ObjectSyncMessage - 8, // 26: spacesync.SpaceSync.ObjectSyncRequestStream:output_type -> spacesync.ObjectSyncMessage - 24, // 27: spacesync.SpaceSync.AclAddRecord:output_type -> spacesync.AclAddRecordResponse - 26, // 28: spacesync.SpaceSync.AclGetRecords:output_type -> spacesync.AclGetRecordsResponse - 21, // [21:29] is the sub-list for method output_type - 13, // [13:21] is the sub-list for method input_type - 13, // [13:13] is the sub-list for extension type_name - 13, // [13:13] is the sub-list for extension extendee - 0, // [0:13] is the sub-list for field type_name + 3, // 5: spacesync.ObjectSyncMessage.objectType:type_name -> spacesync.ObjectType + 14, // 6: spacesync.SpacePushRequest.payload:type_name -> spacesync.SpacePayload + 14, // 7: spacesync.SpacePullResponse.payload:type_name -> spacesync.SpacePayload + 17, // 8: spacesync.SpacePayload.spaceHeader:type_name -> spacesync.RawSpaceHeaderWithId + 19, // 9: spacesync.SpaceSettingsContent.objectDelete:type_name -> spacesync.ObjectDelete + 21, // 10: spacesync.SpaceSettingsContent.spaceDelete:type_name -> spacesync.SpaceDelete + 18, // 11: spacesync.SettingsData.content:type_name -> spacesync.SpaceSettingsContent + 22, // 12: spacesync.SettingsData.snapshot:type_name -> spacesync.SpaceSettingsSnapshot + 1, // 13: spacesync.SpaceSubscription.action:type_name -> spacesync.SpaceSubscriptionAction + 4, // 14: spacesync.StoreDiffRequest.ranges:type_name -> spacesync.HeadSyncRange + 5, // 15: spacesync.StoreDiffResponse.results:type_name -> spacesync.HeadSyncResult + 31, // 16: spacesync.StoreKeyValues.keyValues:type_name -> spacesync.StoreKeyValue + 7, // 17: spacesync.SpaceSync.HeadSync:input_type -> spacesync.HeadSyncRequest + 29, // 18: spacesync.SpaceSync.StoreDiff:input_type -> spacesync.StoreDiffRequest + 31, // 19: spacesync.SpaceSync.StoreElements:input_type -> spacesync.StoreKeyValue + 10, // 20: spacesync.SpaceSync.SpacePush:input_type -> spacesync.SpacePushRequest + 12, // 21: spacesync.SpaceSync.SpacePull:input_type -> spacesync.SpacePullRequest + 9, // 22: spacesync.SpaceSync.ObjectSyncStream:input_type -> spacesync.ObjectSyncMessage + 9, // 23: spacesync.SpaceSync.ObjectSync:input_type -> spacesync.ObjectSyncMessage + 9, // 24: spacesync.SpaceSync.ObjectSyncRequestStream:input_type -> spacesync.ObjectSyncMessage + 25, // 25: spacesync.SpaceSync.AclAddRecord:input_type -> spacesync.AclAddRecordRequest + 27, // 26: spacesync.SpaceSync.AclGetRecords:input_type -> spacesync.AclGetRecordsRequest + 8, // 27: spacesync.SpaceSync.HeadSync:output_type -> spacesync.HeadSyncResponse + 30, // 28: spacesync.SpaceSync.StoreDiff:output_type -> spacesync.StoreDiffResponse + 31, // 29: spacesync.SpaceSync.StoreElements:output_type -> spacesync.StoreKeyValue + 11, // 30: spacesync.SpaceSync.SpacePush:output_type -> spacesync.SpacePushResponse + 13, // 31: spacesync.SpaceSync.SpacePull:output_type -> spacesync.SpacePullResponse + 9, // 32: spacesync.SpaceSync.ObjectSyncStream:output_type -> spacesync.ObjectSyncMessage + 9, // 33: spacesync.SpaceSync.ObjectSync:output_type -> spacesync.ObjectSyncMessage + 9, // 34: spacesync.SpaceSync.ObjectSyncRequestStream:output_type -> spacesync.ObjectSyncMessage + 26, // 35: spacesync.SpaceSync.AclAddRecord:output_type -> spacesync.AclAddRecordResponse + 28, // 36: spacesync.SpaceSync.AclGetRecords:output_type -> spacesync.AclGetRecordsResponse + 27, // [27:37] is the sub-list for method output_type + 17, // [17:27] is the sub-list for method input_type + 17, // [17:17] is the sub-list for extension type_name + 17, // [17:17] is the sub-list for extension extendee + 0, // [0:17] is the sub-list for field type_name } func init() { file_commonspace_spacesyncproto_protos_spacesync_proto_init() } @@ -1868,8 +2409,8 @@ func file_commonspace_spacesyncproto_protos_spacesync_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_commonspace_spacesyncproto_protos_spacesync_proto_rawDesc), len(file_commonspace_spacesyncproto_protos_spacesync_proto_rawDesc)), - NumEnums: 3, - NumMessages: 24, + NumEnums: 4, + NumMessages: 31, NumExtensions: 0, NumServices: 1, }, diff --git a/commonspace/spacesyncproto/spacesync_drpc.pb.go b/commonspace/spacesyncproto/spacesync_drpc.pb.go index e8e92d86..a75904a5 100644 --- a/commonspace/spacesyncproto/spacesync_drpc.pb.go +++ b/commonspace/spacesyncproto/spacesync_drpc.pb.go @@ -34,6 +34,8 @@ type DRPCSpaceSyncClient interface { DRPCConn() drpc.Conn HeadSync(ctx context.Context, in *HeadSyncRequest) (*HeadSyncResponse, error) + StoreDiff(ctx context.Context, in *StoreDiffRequest) (*StoreDiffResponse, error) + StoreElements(ctx context.Context) (DRPCSpaceSync_StoreElementsClient, error) SpacePush(ctx context.Context, in *SpacePushRequest) (*SpacePushResponse, error) SpacePull(ctx context.Context, in *SpacePullRequest) (*SpacePullResponse, error) ObjectSyncStream(ctx context.Context) (DRPCSpaceSync_ObjectSyncStreamClient, error) @@ -62,6 +64,54 @@ func (c *drpcSpaceSyncClient) HeadSync(ctx context.Context, in *HeadSyncRequest) return out, nil } +func (c *drpcSpaceSyncClient) StoreDiff(ctx context.Context, in *StoreDiffRequest) (*StoreDiffResponse, error) { + out := new(StoreDiffResponse) + err := c.cc.Invoke(ctx, "/spacesync.SpaceSync/StoreDiff", drpcEncoding_File_commonspace_spacesyncproto_protos_spacesync_proto{}, in, out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *drpcSpaceSyncClient) StoreElements(ctx context.Context) (DRPCSpaceSync_StoreElementsClient, error) { + stream, err := c.cc.NewStream(ctx, "/spacesync.SpaceSync/StoreElements", drpcEncoding_File_commonspace_spacesyncproto_protos_spacesync_proto{}) + if err != nil { + return nil, err + } + x := &drpcSpaceSync_StoreElementsClient{stream} + return x, nil +} + +type DRPCSpaceSync_StoreElementsClient interface { + drpc.Stream + Send(*StoreKeyValue) error + Recv() (*StoreKeyValue, error) +} + +type drpcSpaceSync_StoreElementsClient struct { + drpc.Stream +} + +func (x *drpcSpaceSync_StoreElementsClient) GetStream() drpc.Stream { + return x.Stream +} + +func (x *drpcSpaceSync_StoreElementsClient) Send(m *StoreKeyValue) error { + return x.MsgSend(m, drpcEncoding_File_commonspace_spacesyncproto_protos_spacesync_proto{}) +} + +func (x *drpcSpaceSync_StoreElementsClient) Recv() (*StoreKeyValue, error) { + m := new(StoreKeyValue) + if err := x.MsgRecv(m, drpcEncoding_File_commonspace_spacesyncproto_protos_spacesync_proto{}); err != nil { + return nil, err + } + return m, nil +} + +func (x *drpcSpaceSync_StoreElementsClient) RecvMsg(m *StoreKeyValue) error { + return x.MsgRecv(m, drpcEncoding_File_commonspace_spacesyncproto_protos_spacesync_proto{}) +} + func (c *drpcSpaceSyncClient) SpacePush(ctx context.Context, in *SpacePushRequest) (*SpacePushResponse, error) { out := new(SpacePushResponse) err := c.cc.Invoke(ctx, "/spacesync.SpaceSync/SpacePush", drpcEncoding_File_commonspace_spacesyncproto_protos_spacesync_proto{}, in, out) @@ -188,6 +238,8 @@ func (c *drpcSpaceSyncClient) AclGetRecords(ctx context.Context, in *AclGetRecor type DRPCSpaceSyncServer interface { HeadSync(context.Context, *HeadSyncRequest) (*HeadSyncResponse, error) + StoreDiff(context.Context, *StoreDiffRequest) (*StoreDiffResponse, error) + StoreElements(DRPCSpaceSync_StoreElementsStream) error SpacePush(context.Context, *SpacePushRequest) (*SpacePushResponse, error) SpacePull(context.Context, *SpacePullRequest) (*SpacePullResponse, error) ObjectSyncStream(DRPCSpaceSync_ObjectSyncStreamStream) error @@ -203,6 +255,14 @@ func (s *DRPCSpaceSyncUnimplementedServer) HeadSync(context.Context, *HeadSyncRe return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) } +func (s *DRPCSpaceSyncUnimplementedServer) StoreDiff(context.Context, *StoreDiffRequest) (*StoreDiffResponse, error) { + return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) +} + +func (s *DRPCSpaceSyncUnimplementedServer) StoreElements(DRPCSpaceSync_StoreElementsStream) error { + return drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) +} + func (s *DRPCSpaceSyncUnimplementedServer) SpacePush(context.Context, *SpacePushRequest) (*SpacePushResponse, error) { return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) } @@ -233,7 +293,7 @@ func (s *DRPCSpaceSyncUnimplementedServer) AclGetRecords(context.Context, *AclGe type DRPCSpaceSyncDescription struct{} -func (DRPCSpaceSyncDescription) NumMethods() int { return 8 } +func (DRPCSpaceSyncDescription) NumMethods() int { return 10 } func (DRPCSpaceSyncDescription) Method(n int) (string, drpc.Encoding, drpc.Receiver, interface{}, bool) { switch n { @@ -247,6 +307,23 @@ func (DRPCSpaceSyncDescription) Method(n int) (string, drpc.Encoding, drpc.Recei ) }, DRPCSpaceSyncServer.HeadSync, true case 1: + return "/spacesync.SpaceSync/StoreDiff", drpcEncoding_File_commonspace_spacesyncproto_protos_spacesync_proto{}, + func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { + return srv.(DRPCSpaceSyncServer). + StoreDiff( + ctx, + in1.(*StoreDiffRequest), + ) + }, DRPCSpaceSyncServer.StoreDiff, true + case 2: + return "/spacesync.SpaceSync/StoreElements", drpcEncoding_File_commonspace_spacesyncproto_protos_spacesync_proto{}, + func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { + return nil, srv.(DRPCSpaceSyncServer). + StoreElements( + &drpcSpaceSync_StoreElementsStream{in1.(drpc.Stream)}, + ) + }, DRPCSpaceSyncServer.StoreElements, true + case 3: return "/spacesync.SpaceSync/SpacePush", drpcEncoding_File_commonspace_spacesyncproto_protos_spacesync_proto{}, func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { return srv.(DRPCSpaceSyncServer). @@ -255,7 +332,7 @@ func (DRPCSpaceSyncDescription) Method(n int) (string, drpc.Encoding, drpc.Recei in1.(*SpacePushRequest), ) }, DRPCSpaceSyncServer.SpacePush, true - case 2: + case 4: return "/spacesync.SpaceSync/SpacePull", drpcEncoding_File_commonspace_spacesyncproto_protos_spacesync_proto{}, func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { return srv.(DRPCSpaceSyncServer). @@ -264,7 +341,7 @@ func (DRPCSpaceSyncDescription) Method(n int) (string, drpc.Encoding, drpc.Recei in1.(*SpacePullRequest), ) }, DRPCSpaceSyncServer.SpacePull, true - case 3: + case 5: return "/spacesync.SpaceSync/ObjectSyncStream", drpcEncoding_File_commonspace_spacesyncproto_protos_spacesync_proto{}, func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { return nil, srv.(DRPCSpaceSyncServer). @@ -272,7 +349,7 @@ func (DRPCSpaceSyncDescription) Method(n int) (string, drpc.Encoding, drpc.Recei &drpcSpaceSync_ObjectSyncStreamStream{in1.(drpc.Stream)}, ) }, DRPCSpaceSyncServer.ObjectSyncStream, true - case 4: + case 6: return "/spacesync.SpaceSync/ObjectSync", drpcEncoding_File_commonspace_spacesyncproto_protos_spacesync_proto{}, func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { return srv.(DRPCSpaceSyncServer). @@ -281,7 +358,7 @@ func (DRPCSpaceSyncDescription) Method(n int) (string, drpc.Encoding, drpc.Recei in1.(*ObjectSyncMessage), ) }, DRPCSpaceSyncServer.ObjectSync, true - case 5: + case 7: return "/spacesync.SpaceSync/ObjectSyncRequestStream", drpcEncoding_File_commonspace_spacesyncproto_protos_spacesync_proto{}, func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { return nil, srv.(DRPCSpaceSyncServer). @@ -290,7 +367,7 @@ func (DRPCSpaceSyncDescription) Method(n int) (string, drpc.Encoding, drpc.Recei &drpcSpaceSync_ObjectSyncRequestStreamStream{in2.(drpc.Stream)}, ) }, DRPCSpaceSyncServer.ObjectSyncRequestStream, true - case 6: + case 8: return "/spacesync.SpaceSync/AclAddRecord", drpcEncoding_File_commonspace_spacesyncproto_protos_spacesync_proto{}, func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { return srv.(DRPCSpaceSyncServer). @@ -299,7 +376,7 @@ func (DRPCSpaceSyncDescription) Method(n int) (string, drpc.Encoding, drpc.Recei in1.(*AclAddRecordRequest), ) }, DRPCSpaceSyncServer.AclAddRecord, true - case 7: + case 9: return "/spacesync.SpaceSync/AclGetRecords", drpcEncoding_File_commonspace_spacesyncproto_protos_spacesync_proto{}, func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { return srv.(DRPCSpaceSyncServer). @@ -333,6 +410,48 @@ func (x *drpcSpaceSync_HeadSyncStream) SendAndClose(m *HeadSyncResponse) error { return x.CloseSend() } +type DRPCSpaceSync_StoreDiffStream interface { + drpc.Stream + SendAndClose(*StoreDiffResponse) error +} + +type drpcSpaceSync_StoreDiffStream struct { + drpc.Stream +} + +func (x *drpcSpaceSync_StoreDiffStream) SendAndClose(m *StoreDiffResponse) error { + if err := x.MsgSend(m, drpcEncoding_File_commonspace_spacesyncproto_protos_spacesync_proto{}); err != nil { + return err + } + return x.CloseSend() +} + +type DRPCSpaceSync_StoreElementsStream interface { + drpc.Stream + Send(*StoreKeyValue) error + Recv() (*StoreKeyValue, error) +} + +type drpcSpaceSync_StoreElementsStream struct { + drpc.Stream +} + +func (x *drpcSpaceSync_StoreElementsStream) Send(m *StoreKeyValue) error { + return x.MsgSend(m, drpcEncoding_File_commonspace_spacesyncproto_protos_spacesync_proto{}) +} + +func (x *drpcSpaceSync_StoreElementsStream) Recv() (*StoreKeyValue, error) { + m := new(StoreKeyValue) + if err := x.MsgRecv(m, drpcEncoding_File_commonspace_spacesyncproto_protos_spacesync_proto{}); err != nil { + return nil, err + } + return m, nil +} + +func (x *drpcSpaceSync_StoreElementsStream) RecvMsg(m *StoreKeyValue) error { + return x.MsgRecv(m, drpcEncoding_File_commonspace_spacesyncproto_protos_spacesync_proto{}) +} + type DRPCSpaceSync_SpacePushStream interface { drpc.Stream SendAndClose(*SpacePushResponse) error diff --git a/commonspace/spacesyncproto/spacesync_vtproto.pb.go b/commonspace/spacesyncproto/spacesync_vtproto.pb.go index 1548307d..10a1426c 100644 --- a/commonspace/spacesyncproto/spacesync_vtproto.pb.go +++ b/commonspace/spacesyncproto/spacesync_vtproto.pb.go @@ -317,6 +317,11 @@ func (m *ObjectSyncMessage) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if m.ObjectType != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.ObjectType)) + i-- + dAtA[i] = 0x30 + } if len(m.ObjectId) > 0 { i -= len(m.ObjectId) copy(dAtA[i:], m.ObjectId) @@ -885,6 +890,53 @@ func (m *ObjectDelete) MarshalToSizedBufferVT(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *StoreHeader) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *StoreHeader) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *StoreHeader) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.StorageName) > 0 { + i -= len(m.StorageName) + copy(dAtA[i:], m.StorageName) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.StorageName))) + i-- + dAtA[i] = 0x12 + } + if len(m.SpaceId) > 0 { + i -= len(m.SpaceId) + copy(dAtA[i:], m.SpaceId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SpaceId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *SpaceDelete) MarshalVT() (dAtA []byte, err error) { if m == nil { return nil, nil @@ -1259,6 +1311,336 @@ func (m *AclGetRecordsResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) return len(dAtA) - i, nil } +func (m *StoreDiffRequest) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *StoreDiffRequest) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *StoreDiffRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Ranges) > 0 { + for iNdEx := len(m.Ranges) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Ranges[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + } + if len(m.SpaceId) > 0 { + i -= len(m.SpaceId) + copy(dAtA[i:], m.SpaceId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SpaceId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *StoreDiffResponse) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *StoreDiffResponse) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *StoreDiffResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Results) > 0 { + for iNdEx := len(m.Results) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Results[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *StoreKeyValue) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *StoreKeyValue) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *StoreKeyValue) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.SpaceId) > 0 { + i -= len(m.SpaceId) + copy(dAtA[i:], m.SpaceId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SpaceId))) + i-- + dAtA[i] = 0x2a + } + if len(m.PeerSignature) > 0 { + i -= len(m.PeerSignature) + copy(dAtA[i:], m.PeerSignature) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PeerSignature))) + i-- + dAtA[i] = 0x22 + } + if len(m.IdentitySignature) > 0 { + i -= len(m.IdentitySignature) + copy(dAtA[i:], m.IdentitySignature) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.IdentitySignature))) + i-- + dAtA[i] = 0x1a + } + if len(m.Value) > 0 { + i -= len(m.Value) + copy(dAtA[i:], m.Value) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Value))) + i-- + dAtA[i] = 0x12 + } + if len(m.KeyPeerId) > 0 { + i -= len(m.KeyPeerId) + copy(dAtA[i:], m.KeyPeerId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.KeyPeerId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *StoreKeyValues) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *StoreKeyValues) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *StoreKeyValues) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.KeyValues) > 0 { + for iNdEx := len(m.KeyValues) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.KeyValues[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *StoreKeyInner) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *StoreKeyInner) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *StoreKeyInner) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Key) > 0 { + i -= len(m.Key) + copy(dAtA[i:], m.Key) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Key))) + i-- + dAtA[i] = 0x32 + } + if len(m.AclHeadId) > 0 { + i -= len(m.AclHeadId) + copy(dAtA[i:], m.AclHeadId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.AclHeadId))) + i-- + dAtA[i] = 0x2a + } + if m.TimestampMicro != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.TimestampMicro)) + i-- + dAtA[i] = 0x20 + } + if len(m.Value) > 0 { + i -= len(m.Value) + copy(dAtA[i:], m.Value) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Value))) + i-- + dAtA[i] = 0x1a + } + if len(m.Identity) > 0 { + i -= len(m.Identity) + copy(dAtA[i:], m.Identity) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Identity))) + i-- + dAtA[i] = 0x12 + } + if len(m.Peer) > 0 { + i -= len(m.Peer) + copy(dAtA[i:], m.Peer) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Peer))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *StorageHeader) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *StorageHeader) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *StorageHeader) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.StorageName) > 0 { + i -= len(m.StorageName) + copy(dAtA[i:], m.StorageName) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.StorageName))) + i-- + dAtA[i] = 0x12 + } + if len(m.SpaceId) > 0 { + i -= len(m.SpaceId) + copy(dAtA[i:], m.SpaceId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SpaceId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *HeadSyncRange) SizeVT() (n int) { if m == nil { return 0 @@ -1390,6 +1772,9 @@ func (m *ObjectSyncMessage) SizeVT() (n int) { if l > 0 { n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } + if m.ObjectType != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.ObjectType)) + } n += len(m.unknownFields) return n } @@ -1603,6 +1988,24 @@ func (m *ObjectDelete) SizeVT() (n int) { return n } +func (m *StoreHeader) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.SpaceId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.StorageName) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + func (m *SpaceDelete) SizeVT() (n int) { if m == nil { return 0 @@ -1746,6 +2149,139 @@ func (m *AclGetRecordsResponse) SizeVT() (n int) { return n } +func (m *StoreDiffRequest) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.SpaceId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if len(m.Ranges) > 0 { + for _, e := range m.Ranges { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *StoreDiffResponse) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Results) > 0 { + for _, e := range m.Results { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *StoreKeyValue) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.KeyPeerId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.Value) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.IdentitySignature) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.PeerSignature) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.SpaceId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *StoreKeyValues) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.KeyValues) > 0 { + for _, e := range m.KeyValues { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *StoreKeyInner) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Peer) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.Identity) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.Value) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.TimestampMicro != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.TimestampMicro)) + } + l = len(m.AclHeadId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.Key) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *StorageHeader) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.SpaceId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.StorageName) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + func (m *HeadSyncRange) UnmarshalVT(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -2558,6 +3094,25 @@ func (m *ObjectSyncMessage) UnmarshalVT(dAtA []byte) error { } m.ObjectId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ObjectType", wireType) + } + m.ObjectType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ObjectType |= ObjectType(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) @@ -3816,6 +4371,121 @@ func (m *ObjectDelete) UnmarshalVT(dAtA []byte) error { } return nil } +func (m *StoreHeader) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: StoreHeader: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StoreHeader: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SpaceId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SpaceId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StorageName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.StorageName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *SpaceDelete) UnmarshalVT(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -4669,3 +5339,858 @@ func (m *AclGetRecordsResponse) UnmarshalVT(dAtA []byte) error { } return nil } +func (m *StoreDiffRequest) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: StoreDiffRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StoreDiffRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SpaceId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SpaceId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Ranges", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Ranges = append(m.Ranges, &HeadSyncRange{}) + if err := m.Ranges[len(m.Ranges)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *StoreDiffResponse) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: StoreDiffResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StoreDiffResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Results", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Results = append(m.Results, &HeadSyncResult{}) + if err := m.Results[len(m.Results)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *StoreKeyValue) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: StoreKeyValue: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StoreKeyValue: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field KeyPeerId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.KeyPeerId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Value = append(m.Value[:0], dAtA[iNdEx:postIndex]...) + if m.Value == nil { + m.Value = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field IdentitySignature", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.IdentitySignature = append(m.IdentitySignature[:0], dAtA[iNdEx:postIndex]...) + if m.IdentitySignature == nil { + m.IdentitySignature = []byte{} + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PeerSignature", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PeerSignature = append(m.PeerSignature[:0], dAtA[iNdEx:postIndex]...) + if m.PeerSignature == nil { + m.PeerSignature = []byte{} + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SpaceId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SpaceId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *StoreKeyValues) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: StoreKeyValues: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StoreKeyValues: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field KeyValues", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.KeyValues = append(m.KeyValues, &StoreKeyValue{}) + if err := m.KeyValues[len(m.KeyValues)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *StoreKeyInner) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: StoreKeyInner: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StoreKeyInner: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Peer", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Peer = append(m.Peer[:0], dAtA[iNdEx:postIndex]...) + if m.Peer == nil { + m.Peer = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Identity", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Identity = append(m.Identity[:0], dAtA[iNdEx:postIndex]...) + if m.Identity == nil { + m.Identity = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Value = append(m.Value[:0], dAtA[iNdEx:postIndex]...) + if m.Value == nil { + m.Value = []byte{} + } + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TimestampMicro", wireType) + } + m.TimestampMicro = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TimestampMicro |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AclHeadId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AclHeadId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Key = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *StorageHeader) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: StorageHeader: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StorageHeader: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SpaceId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SpaceId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StorageName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.StorageName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} diff --git a/commonspace/spaceutils_test.go b/commonspace/spaceutils_test.go index 846cc084..558ea158 100644 --- a/commonspace/spaceutils_test.go +++ b/commonspace/spaceutils_test.go @@ -2,12 +2,14 @@ package commonspace import ( "context" + "errors" "fmt" "math/rand" "sync" "testing" "time" + anystore "github.com/anyproto/any-store" "github.com/anyproto/go-chash" "github.com/stretchr/testify/require" "go.uber.org/zap" @@ -26,6 +28,7 @@ import ( "github.com/anyproto/any-sync/commonspace/object/treesyncer" "github.com/anyproto/any-sync/commonspace/objecttreebuilder" "github.com/anyproto/any-sync/commonspace/peermanager" + "github.com/anyproto/any-sync/commonspace/spacepayloads" "github.com/anyproto/any-sync/commonspace/spacestorage" "github.com/anyproto/any-sync/commonspace/spacesyncproto" "github.com/anyproto/any-sync/commonspace/sync/objectsync/objectmessages" @@ -751,7 +754,7 @@ func newMultiPeerFixture(t *testing.T, peerNum int) *multiPeerFixture { require.NoError(t, err) readKey := crypto.NewAES() meta := []byte("account") - payload := SpaceCreatePayload{ + payload := spacepayloads.SpaceCreatePayload{ SigningKey: keys.SignKey, SpaceType: "space", ReplicationKey: 10, @@ -761,7 +764,7 @@ func newMultiPeerFixture(t *testing.T, peerNum int) *multiPeerFixture { MetadataKey: metaKey, Metadata: meta, } - createSpace, err := StoragePayloadForSpaceCreate(payload) + createSpace, err := spacepayloads.StoragePayloadForSpaceCreate(payload) require.NoError(t, err) executor := list.NewExternalKeysAclExecutor(createSpace.SpaceHeaderWithId.Id, keys, meta, createSpace.AclWithId) cmds := []string{ @@ -802,6 +805,9 @@ func newMultiPeerFixture(t *testing.T, peerNum int) *multiPeerFixture { err := listStorage.AddAll(ctx, []list.StorageRecord{ {RawRecord: rec.Payload, Id: rec.Id, PrevId: prevRec, Order: i + 1, ChangeSize: len(rec.Payload)}, }) + if errors.Is(err, anystore.ErrDocExists) { + continue + } require.NoError(t, err) } } diff --git a/commonspace/sync/objectsync/objectmessages/headupdate.go b/commonspace/sync/objectsync/objectmessages/headupdate.go index a3e07c15..4b5cb438 100644 --- a/commonspace/sync/objectsync/objectmessages/headupdate.go +++ b/commonspace/sync/objectsync/objectmessages/headupdate.go @@ -39,6 +39,7 @@ type InnerHeadUpdate interface { Prepare() error Heads() []string MsgSize() uint64 + ObjectType() spacesyncproto.ObjectType } type ObjectMeta struct { @@ -48,10 +49,11 @@ type ObjectMeta struct { } type HeadUpdate struct { - Meta ObjectMeta - Bytes []byte - Update InnerHeadUpdate - msg *spacesyncproto.ObjectSyncMessage + Meta ObjectMeta + Bytes []byte + Update InnerHeadUpdate + objectType spacesyncproto.ObjectType + msg *spacesyncproto.ObjectSyncMessage } func (h *HeadUpdate) MsgSize() uint64 { @@ -84,6 +86,7 @@ func (h *HeadUpdate) SetProtoMessage(message protobuf.Message) error { h.Bytes = msg.GetPayload() h.Meta.SpaceId = msg.SpaceId h.Meta.ObjectId = msg.ObjectId + h.objectType = msg.GetObjectType() return nil } @@ -94,14 +97,19 @@ func (h *HeadUpdate) ProtoMessage() (protobuf.Message, error) { return nil, err } return &spacesyncproto.ObjectSyncMessage{ - SpaceId: h.Meta.SpaceId, - Payload: payload, - ObjectId: h.Meta.ObjectId, + SpaceId: h.Meta.SpaceId, + Payload: payload, + ObjectId: h.Meta.ObjectId, + ObjectType: h.Update.ObjectType(), }, nil } return NewMessage(), nil } +func (h *HeadUpdate) ObjectType() spacesyncproto.ObjectType { + return h.objectType +} + func (h *HeadUpdate) SpaceId() string { return h.Meta.SpaceId } @@ -116,9 +124,10 @@ func (h *HeadUpdate) ObjectId() string { func (h *HeadUpdate) Copy() drpc.Message { return &HeadUpdate{ - Meta: h.Meta, - Bytes: h.Bytes, - Update: h.Update, - msg: h.msg, + Meta: h.Meta, + Bytes: h.Bytes, + Update: h.Update, + msg: h.msg, + objectType: h.objectType, } } diff --git a/commonspace/sync/objectsync/objectsync_test.go b/commonspace/sync/objectsync/objectsync_test.go index c997ffd6..1062538e 100644 --- a/commonspace/sync/objectsync/objectsync_test.go +++ b/commonspace/sync/objectsync/objectsync_test.go @@ -10,6 +10,8 @@ import ( "go.uber.org/mock/gomock" "github.com/anyproto/any-sync/app" + "github.com/anyproto/any-sync/commonspace/object/keyvalue/kvinterfaces" + "github.com/anyproto/any-sync/commonspace/object/keyvalue/kvinterfaces/mock_kvinterfaces" "github.com/anyproto/any-sync/commonspace/object/tree/synctree" "github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto" "github.com/anyproto/any-sync/commonspace/object/treemanager" @@ -159,6 +161,7 @@ func TestObjectSync_ApplyRequest(t *testing.T) { type fixture struct { *objectSync objectManager *mock_objectmanager.MockObjectManager + keyValue *mock_kvinterfaces.MockKeyValueService pool *mock_pool.MockService a *app.App ctrl *gomock.Controller @@ -171,13 +174,16 @@ func newFixture(t *testing.T) *fixture { fx.ctrl = gomock.NewController(t) fx.objectManager = mock_objectmanager.NewMockObjectManager(fx.ctrl) fx.pool = mock_pool.NewMockService(fx.ctrl) + fx.keyValue = mock_kvinterfaces.NewMockKeyValueService(fx.ctrl) anymock.ExpectComp(fx.objectManager.EXPECT(), treemanager.CName) anymock.ExpectComp(fx.pool.EXPECT(), pool.CName) + anymock.ExpectComp(fx.keyValue.EXPECT(), kvinterfaces.CName) fx.objectSync = &objectSync{} spaceState := &spacestate.SpaceState{SpaceId: "spaceId"} fx.a.Register(fx.objectManager). Register(spaceState). Register(fx.pool). + Register(fx.keyValue). Register(syncstatus.NewNoOpSyncStatus()). Register(fx.objectSync) require.NoError(t, fx.a.Start(context.Background())) diff --git a/commonspace/sync/objectsync/synchandler.go b/commonspace/sync/objectsync/synchandler.go index 53168410..89509bf6 100644 --- a/commonspace/sync/objectsync/synchandler.go +++ b/commonspace/sync/objectsync/synchandler.go @@ -11,6 +11,7 @@ import ( "github.com/anyproto/any-sync/app" "github.com/anyproto/any-sync/app/logger" + "github.com/anyproto/any-sync/commonspace/object/keyvalue/kvinterfaces" "github.com/anyproto/any-sync/commonspace/object/tree/synctree" "github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto" "github.com/anyproto/any-sync/commonspace/object/treemanager" @@ -30,10 +31,11 @@ var ErrUnexpectedHeadUpdateType = errors.New("unexpected head update type") var log = logger.NewNamed(syncdeps.CName) type objectSync struct { - spaceId string - pool pool.Service - manager objectmanager.ObjectManager - status syncstatus.StatusUpdater + spaceId string + pool pool.Service + manager objectmanager.ObjectManager + status syncstatus.StatusUpdater + keyValue kvinterfaces.KeyValueService } func New() syncdeps.SyncHandler { @@ -43,6 +45,7 @@ func New() syncdeps.SyncHandler { func (o *objectSync) Init(a *app.App) (err error) { o.manager = a.MustComponent(treemanager.CName).(objectmanager.ObjectManager) o.pool = a.MustComponent(pool.CName).(pool.Service) + o.keyValue = a.MustComponent(kvinterfaces.CName).(kvinterfaces.KeyValueService) o.status = a.MustComponent(syncstatus.CName).(syncstatus.StatusUpdater) o.spaceId = a.MustComponent(spacestate.CName).(*spacestate.SpaceState).SpaceId return @@ -57,6 +60,9 @@ func (o *objectSync) HandleHeadUpdate(ctx context.Context, headUpdate drpc.Messa if !ok { return nil, ErrUnexpectedHeadUpdateType } + if update.ObjectType() == spacesyncproto.ObjectType_KeyValue { + return nil, o.keyValue.HandleMessage(ctx, update) + } peerId, err := peer.CtxPeerId(ctx) if err != nil { return nil, err diff --git a/commonspace/sync/sync_test.go b/commonspace/sync/sync_test.go index 530c315b..7fef6775 100644 --- a/commonspace/sync/sync_test.go +++ b/commonspace/sync/sync_test.go @@ -391,7 +391,12 @@ func (r *testRequest) MsgSize() uint64 { } type testMessage struct { - objectId string + objectId string + objectType spacesyncproto.ObjectType +} + +func (t *testMessage) ObjectType() spacesyncproto.ObjectType { + return t.objectType } func (t *testMessage) ObjectId() string { diff --git a/commonspace/sync/syncdeps/message.go b/commonspace/sync/syncdeps/message.go index c1844098..26a0fac3 100644 --- a/commonspace/sync/syncdeps/message.go +++ b/commonspace/sync/syncdeps/message.go @@ -1,6 +1,9 @@ package syncdeps +import "github.com/anyproto/any-sync/commonspace/spacesyncproto" + type Message interface { ObjectId() string MsgSize() uint64 + ObjectType() spacesyncproto.ObjectType } diff --git a/go.mod b/go.mod index 44fdc9a9..8eb0956b 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/anyproto/any-sync -go 1.23.2 +go 1.23.0 + +toolchain go1.24.1 require ( filippo.io/edwards25519 v1.1.0 @@ -23,25 +25,25 @@ require ( github.com/ipfs/go-block-format v0.2.0 github.com/ipfs/go-cid v0.5.0 github.com/ipfs/go-ipld-format v0.6.0 - github.com/libp2p/go-libp2p v0.41.0 + github.com/libp2p/go-libp2p v0.41.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/planetscale/vtprotobuf v0.6.0 - github.com/prometheus/client_golang v1.21.1 - github.com/quic-go/quic-go v0.50.1 + github.com/prometheus/client_golang v1.22.0 + github.com/quic-go/quic-go v0.51.0 github.com/stretchr/testify v1.10.0 github.com/tyler-smith/go-bip39 v1.1.0 github.com/zeebo/blake3 v0.2.4 go.uber.org/atomic v1.11.0 - go.uber.org/mock v0.5.0 + go.uber.org/mock v0.5.2 go.uber.org/zap v1.27.0 - golang.org/x/crypto v0.36.0 + golang.org/x/crypto v0.38.0 golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 - golang.org/x/net v0.37.0 - golang.org/x/sys v0.31.0 + golang.org/x/net v0.40.0 + golang.org/x/sys v0.33.0 golang.org/x/time v0.11.0 - golang.org/x/tools v0.31.0 + golang.org/x/tools v0.33.0 google.golang.org/protobuf v1.36.5 gopkg.in/yaml.v3 v3.0.1 storj.io/drpc v0.0.34 @@ -77,7 +79,6 @@ require ( github.com/ipld/go-codec-dagpb v1.6.0 // indirect github.com/ipld/go-ipld-prime v0.21.0 // indirect github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect - github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -109,8 +110,8 @@ require ( go.uber.org/multierr v1.11.0 // indirect golang.org/x/image v0.21.0 // indirect golang.org/x/mod v0.24.0 // indirect - golang.org/x/sync v0.12.0 // indirect - golang.org/x/text v0.23.0 // indirect + golang.org/x/sync v0.14.0 // indirect + golang.org/x/text v0.25.0 // indirect lukechampine.com/blake3 v1.4.0 // indirect modernc.org/libc v1.61.13 // indirect modernc.org/mathutil v1.7.1 // indirect diff --git a/go.sum b/go.sum index fe3ee0b4..9aa1bbec 100644 --- a/go.sum +++ b/go.sum @@ -96,8 +96,8 @@ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGw github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/pprof v0.0.0-20250208200701-d0013a598941 h1:43XjGa6toxLpeksjcxs1jIoIyr+vUfOqY2c6HB4bpoc= @@ -182,8 +182,8 @@ github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6 github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/libp2p/go-flow-metrics v0.2.0 h1:EIZzjmeOE6c8Dav0sNv35vhZxATIXWZg6j/C08XmmDw= github.com/libp2p/go-flow-metrics v0.2.0/go.mod h1:st3qqfu8+pMfh+9Mzqb2GTiwrAGjIPszEjZmtksN8Jc= -github.com/libp2p/go-libp2p v0.41.0 h1:JRaD39dqf/tBBGapJ0T38N73vOaDCsWgcx3mE6HgXWk= -github.com/libp2p/go-libp2p v0.41.0/go.mod h1:Be8QYqC4JW6Xq8buukNeoZJjyT1XUDcGoIooCHm1ye4= +github.com/libp2p/go-libp2p v0.41.1 h1:8ecNQVT5ev/jqALTvisSJeVNvXYJyK4NhQx1nNRXQZE= +github.com/libp2p/go-libp2p v0.41.1/go.mod h1:DcGTovJzQl/I7HMrby5ZRjeD0kQkGiy+9w6aEkSZpRI= 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.3.1 h1:cly48Xi5GjNw5Wq+7gmjfBiG9HCzQVkiZOUZ8kUl+Fg= @@ -244,8 +244,8 @@ github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk= github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= github.com/pion/dtls/v3 v3.0.4 h1:44CZekewMzfrn9pmGrj5BNnTMDCFwr+6sLH+cCuLM7U= github.com/pion/dtls/v3 v3.0.4/go.mod h1:R373CsjxWqNPf6MEkfdy3aSe9niZvL/JaKlGeFphtMg= -github.com/pion/ice/v4 v4.0.6 h1:jmM9HwI9lfetQV/39uD0nY4y++XZNPhvzIPCb8EwxUM= -github.com/pion/ice/v4 v4.0.6/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw= +github.com/pion/ice/v4 v4.0.8 h1:ajNx0idNG+S+v9Phu4LSn2cs8JEfTsA1/tEjkkAVpFY= +github.com/pion/ice/v4 v4.0.8/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw= github.com/pion/interceptor v0.1.37 h1:aRA8Zpab/wE7/c0O3fh1PqY0AJI3fCSEM5lRWJVorwI= github.com/pion/interceptor v0.1.37/go.mod h1:JzxbJ4umVTlZAf+/utHzNesY8tmRkM2lVmkS82TTj8Y= github.com/pion/logging v0.2.3 h1:gHuf0zpoh1GW67Nr6Gj4cv5Z9ZscU7g/EaoC/Ke/igI= @@ -258,8 +258,8 @@ github.com/pion/rtcp v1.2.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo= github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0= github.com/pion/rtp v1.8.11 h1:17xjnY5WO5hgO6SD3/NTIUPvSFw/PbLsIJyz1r1yNIk= github.com/pion/rtp v1.8.11/go.mod h1:8uMBJj32Pa1wwx8Fuv/AsFhn8jsgw+3rUC2PfoBZ8p4= -github.com/pion/sctp v1.8.36 h1:owNudmnz1xmhfYje5L/FCav3V9wpPRePHle3Zi+P+M0= -github.com/pion/sctp v1.8.36/go.mod h1:cNiLdchXra8fHQwmIoqw0MbLLMs+f7uQ+dGMG2gWebE= +github.com/pion/sctp v1.8.37 h1:ZDmGPtRPX9mKCiVXtMbTWybFw3z/hVKAZgU81wcOrqs= +github.com/pion/sctp v1.8.37/go.mod h1:cNiLdchXra8fHQwmIoqw0MbLLMs+f7uQ+dGMG2gWebE= github.com/pion/sdp/v3 v3.0.10 h1:6MChLE/1xYB+CjumMw+gZ9ufp2DPApuVSnDT8t5MIgA= github.com/pion/sdp/v3 v3.0.10/go.mod h1:88GMahN5xnScv1hIMTqLdu/cOcUkj6a9ytbncwMCq2E= github.com/pion/srtp/v3 v3.0.4 h1:2Z6vDVxzrX3UHEgrUyIGM4rRouoC7v+NiF1IHtp9B5M= @@ -283,8 +283,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= -github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= +github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= +github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= 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.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= @@ -293,8 +293,8 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= -github.com/quic-go/quic-go v0.50.1 h1:unsgjFIUqW8a2oopkY7YNONpV1gYND6Nt9hnt1PN94Q= -github.com/quic-go/quic-go v0.50.1/go.mod h1:Vim6OmUvlYdwBhXP9ZVrtGmCMWa3wEqhq3NgYrI8b4E= +github.com/quic-go/quic-go v0.51.0 h1:K8exxe9zXxeRKxaXxi/GpUqYiTrtdiWP8bo1KFya6Wc= +github.com/quic-go/quic-go v0.51.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ= github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66 h1:4WFk6u3sOT6pLa1kQ50ZVdm8BQFgJNA117cepZxtLIg= github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66/go.mod h1:Vp72IJajgeOL6ddqrAhmp7IM9zbTcgkQxD/YdxrVwMw= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= @@ -361,8 +361,8 @@ go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0 go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= -go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= +go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= +go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= @@ -375,8 +375,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.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= -golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= +golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw= golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -391,13 +391,13 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= -golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= 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-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= -golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= +golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -407,13 +407,13 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 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.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -421,8 +421,8 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU= -golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ= +golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= +golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/net/secureservice/secureservice.go b/net/secureservice/secureservice.go index 046434ab..3f38e5da 100644 --- a/net/secureservice/secureservice.go +++ b/net/secureservice/secureservice.go @@ -30,12 +30,14 @@ var ( // ProtoVersion 3 - acl with breaking changes / multiplayer // ProtoVersion 4 - new sync compatible version // ProtoVersion 5 - sync with no entry space + // ProtoVersion 6 - sync with key value messages CompatibleVersion = uint32(4) ProtoVersion = uint32(5) + KeyValueVersion = uint32(6) ) var ( - compatibleVersions = []uint32{CompatibleVersion, ProtoVersion} + compatibleVersions = []uint32{CompatibleVersion, ProtoVersion, KeyValueVersion} ) func New() SecureService { diff --git a/paymentservice/paymentserviceproto/paymentservice_tiers.pb.go b/paymentservice/paymentserviceproto/paymentservice_tiers.pb.go index a22709e8..4f05f8ee 100644 --- a/paymentservice/paymentserviceproto/paymentservice_tiers.pb.go +++ b/paymentservice/paymentserviceproto/paymentservice_tiers.pb.go @@ -272,8 +272,10 @@ type TierData struct { // Android platform-specific data: AndroidProductId string `protobuf:"bytes,18,opt,name=androidProductId,proto3" json:"androidProductId,omitempty"` AndroidManageUrl string `protobuf:"bytes,19,opt,name=androidManageUrl,proto3" json:"androidManageUrl,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // something like "limited offer", etc + Offer string `protobuf:"bytes,20,opt,name=offer,proto3" json:"offer,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *TierData) Reset() { @@ -439,6 +441,13 @@ func (x *TierData) GetAndroidManageUrl() string { return "" } +func (x *TierData) GetOffer() string { + if x != nil { + return x.Offer + } + return "" +} + type GetTiersResponse struct { state protoimpl.MessageState `protogen:"open.v1"` // list of all available tiers @@ -504,7 +513,7 @@ var file_paymentservice_paymentserviceproto_protos_paymentservice_tiers_proto_ra 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, - 0xc1, 0x05, 0x0a, 0x08, 0x54, 0x69, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x12, 0x0e, 0x0a, 0x02, + 0xd7, 0x05, 0x0a, 0x08, 0x54, 0x69, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, @@ -548,22 +557,23 @@ var file_paymentservice_paymentserviceproto_protos_paymentservice_tiers_proto_ra 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x64, 0x12, 0x2a, 0x0a, 0x10, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x55, 0x72, 0x6c, 0x18, 0x13, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, - 0x55, 0x72, 0x6c, 0x22, 0x33, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x54, 0x69, 0x65, 0x72, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x05, 0x74, 0x69, 0x65, 0x72, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x54, 0x69, 0x65, 0x72, 0x44, 0x61, 0x74, - 0x61, 0x52, 0x05, 0x74, 0x69, 0x65, 0x72, 0x73, 0x2a, 0x90, 0x01, 0x0a, 0x0a, 0x50, 0x65, 0x72, - 0x69, 0x6f, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x15, 0x0a, 0x11, 0x50, 0x65, 0x72, 0x69, 0x6f, - 0x64, 0x54, 0x79, 0x70, 0x65, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x17, - 0x0a, 0x13, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x54, 0x79, 0x70, 0x65, 0x55, 0x6e, 0x6c, 0x69, - 0x6d, 0x69, 0x74, 0x65, 0x64, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x50, 0x65, 0x72, 0x69, 0x6f, - 0x64, 0x54, 0x79, 0x70, 0x65, 0x44, 0x61, 0x79, 0x73, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x50, - 0x65, 0x72, 0x69, 0x6f, 0x64, 0x54, 0x79, 0x70, 0x65, 0x57, 0x65, 0x65, 0x6b, 0x73, 0x10, 0x03, - 0x12, 0x14, 0x0a, 0x10, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x54, 0x79, 0x70, 0x65, 0x4d, 0x6f, - 0x6e, 0x74, 0x68, 0x73, 0x10, 0x04, 0x12, 0x13, 0x0a, 0x0f, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, - 0x54, 0x79, 0x70, 0x65, 0x59, 0x65, 0x61, 0x72, 0x73, 0x10, 0x05, 0x42, 0x24, 0x5a, 0x22, 0x70, - 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x70, 0x61, - 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x55, 0x72, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x18, 0x14, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x22, 0x33, 0x0a, 0x10, 0x47, 0x65, 0x74, + 0x54, 0x69, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, + 0x05, 0x74, 0x69, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x54, + 0x69, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x52, 0x05, 0x74, 0x69, 0x65, 0x72, 0x73, 0x2a, 0x90, + 0x01, 0x0a, 0x0a, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x15, 0x0a, + 0x11, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x54, 0x79, 0x70, 0x65, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, + 0x77, 0x6e, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x54, 0x79, + 0x70, 0x65, 0x55, 0x6e, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x10, 0x01, 0x12, 0x12, 0x0a, + 0x0e, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x54, 0x79, 0x70, 0x65, 0x44, 0x61, 0x79, 0x73, 0x10, + 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x54, 0x79, 0x70, 0x65, 0x57, + 0x65, 0x65, 0x6b, 0x73, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, + 0x54, 0x79, 0x70, 0x65, 0x4d, 0x6f, 0x6e, 0x74, 0x68, 0x73, 0x10, 0x04, 0x12, 0x13, 0x0a, 0x0f, + 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x54, 0x79, 0x70, 0x65, 0x59, 0x65, 0x61, 0x72, 0x73, 0x10, + 0x05, 0x42, 0x24, 0x5a, 0x22, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x2f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, }) var ( diff --git a/paymentservice/paymentserviceproto/paymentservice_tiers_vtproto.pb.go b/paymentservice/paymentserviceproto/paymentservice_tiers_vtproto.pb.go index 312888bd..a159d636 100644 --- a/paymentservice/paymentserviceproto/paymentservice_tiers_vtproto.pb.go +++ b/paymentservice/paymentserviceproto/paymentservice_tiers_vtproto.pb.go @@ -182,6 +182,15 @@ func (m *TierData) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if len(m.Offer) > 0 { + i -= len(m.Offer) + copy(dAtA[i:], m.Offer) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Offer))) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xa2 + } if len(m.AndroidManageUrl) > 0 { i -= len(m.AndroidManageUrl) copy(dAtA[i:], m.AndroidManageUrl) @@ -498,6 +507,10 @@ func (m *TierData) SizeVT() (n int) { if l > 0 { n += 2 + l + protohelpers.SizeOfVarint(uint64(l)) } + l = len(m.Offer) + if l > 0 { + n += 2 + l + protohelpers.SizeOfVarint(uint64(l)) + } n += len(m.unknownFields) return n } @@ -1360,6 +1373,38 @@ func (m *TierData) UnmarshalVT(dAtA []byte) error { } m.AndroidManageUrl = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 20: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Offer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Offer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) diff --git a/paymentservice/paymentserviceproto/protos/paymentservice_tiers.proto b/paymentservice/paymentserviceproto/protos/paymentservice_tiers.proto index 6cd66399..898e0e7a 100644 --- a/paymentservice/paymentserviceproto/protos/paymentservice_tiers.proto +++ b/paymentservice/paymentserviceproto/protos/paymentservice_tiers.proto @@ -73,6 +73,9 @@ message TierData { // Android platform-specific data: string androidProductId = 18; string androidManageUrl = 19; + + // something like "limited offer", etc + string offer = 20; } message GetTiersResponse { diff --git a/util/crypto/derived.go b/util/crypto/derived.go index 0318b17a..86f64d0d 100644 --- a/util/crypto/derived.go +++ b/util/crypto/derived.go @@ -5,8 +5,9 @@ import ( ) const ( - AnysyncSpacePath = "m/SLIP-0021/anysync/space" - AnysyncTreePath = "m/SLIP-0021/anysync/tree/%s" + AnysyncSpacePath = "m/SLIP-0021/anysync/space" + AnysyncTreePath = "m/SLIP-0021/anysync/tree/%s" + AnysyncKeyValuePath = "m/SLIP-0021/anysync/keyvalue/%s" ) // DeriveSymmetricKey derives a symmetric key from seed and path using slip-21