diff --git a/client/api/controller.go b/client/api/controller.go index e39e3fc4..51629007 100644 --- a/client/api/controller.go +++ b/client/api/controller.go @@ -1,7 +1,9 @@ package api type Controller interface { - CreateDerivedSpace() (id string, err error) + // DeriveSpace derives the space from current account + DeriveSpace() (id string, err error) + // CreateSpace creates new space with random data CreateSpace() (id string, err error) GetAllSpacesIds() (ids []string, err error) // LoadSpace asks node to load a particular space diff --git a/client/clientspace/clientcache/treecache.go b/client/clientspace/clientcache/treecache.go index eee57452..01e230b2 100644 --- a/client/clientspace/clientcache/treecache.go +++ b/client/clientspace/clientcache/treecache.go @@ -7,7 +7,6 @@ import ( "github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger" "github.com/anytypeio/go-anytype-infrastructure-experiments/client/clientspace" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/cache" - "github.com/anytypeio/go-anytype-infrastructure-experiments/node/nodespace" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/ocache" "time" ) @@ -40,7 +39,7 @@ func (c *treeCache) Close(ctx context.Context) (err error) { } func (c *treeCache) Init(a *app.App) (err error) { - c.clientService = a.MustComponent(nodespace.CName).(nodespace.Service) + c.clientService = a.MustComponent(clientspace.CName).(clientspace.Service) c.cache = ocache.New( func(ctx context.Context, id string) (value ocache.Object, err error) { spaceId := ctx.Value(spaceKey).(string) diff --git a/client/clientspace/service.go b/client/clientspace/service.go index 3fcebc1b..4da8b2e8 100644 --- a/client/clientspace/service.go +++ b/client/clientspace/service.go @@ -23,6 +23,8 @@ func New() Service { type Service interface { GetSpace(ctx context.Context, id string) (commonspace.Space, error) + CreateSpace(ctx context.Context, payload commonspace.SpaceCreatePayload) (commonspace.Space, error) + DeriveSpace(ctx context.Context, payload commonspace.SpaceDerivePayload) (commonspace.Space, error) app.ComponentRunnable } @@ -61,6 +63,32 @@ func (s *service) Run(ctx context.Context) (err error) { return } +func (s *service) CreateSpace(ctx context.Context, payload commonspace.SpaceCreatePayload) (space commonspace.Space, err error) { + id, err := s.commonSpace.CreateSpace(ctx, payload) + if err != nil { + return + } + + obj, err := s.commonSpace.GetSpace(ctx, id) + if err != nil { + return + } + return obj.(commonspace.Space), nil +} + +func (s *service) DeriveSpace(ctx context.Context, payload commonspace.SpaceDerivePayload) (space commonspace.Space, err error) { + id, err := s.commonSpace.DeriveSpace(ctx, payload) + if err != nil { + return + } + + obj, err := s.commonSpace.GetSpace(ctx, id) + if err != nil { + return + } + return obj.(commonspace.Space), nil +} + func (s *service) GetSpace(ctx context.Context, id string) (commonspace.Space, error) { v, err := s.spaceCache.Get(ctx, id) if err != nil { diff --git a/client/document/service.go b/client/document/service.go new file mode 100644 index 00000000..afd16366 --- /dev/null +++ b/client/document/service.go @@ -0,0 +1,13 @@ +package document + +import "github.com/anytypeio/go-anytype-infrastructure-experiments/app" + +type Service interface { + app.Component + CreateDocument(spaceId string) (id string, err error) + GetAllDocumentIds(spaceId string) (ids []string, err error) + AddText(documentId, text string) (err error) + DumpDocumentTree(documentId string) (err error) +} + +const CName = "client.document" diff --git a/client/badgerprovider/helpers.go b/client/storage/helpers.go similarity index 61% rename from client/badgerprovider/helpers.go rename to client/storage/helpers.go index afaf5da4..d1d5915a 100644 --- a/client/badgerprovider/helpers.go +++ b/client/storage/helpers.go @@ -1,26 +1,23 @@ -package badgerprovider +package storage import ( - "errors" "github.com/dgraph-io/badger/v3" ) -var ErrIncorrectKey = errors.New("the key is incorrect") - -func Has(db *badger.DB, key []byte) bool { +func hasDB(db *badger.DB, key []byte) bool { return db.View(func(txn *badger.Txn) error { _, err := txn.Get(key) return err }) == nil } -func Put(db *badger.DB, key, value []byte) (err error) { +func putDB(db *badger.DB, key, value []byte) (err error) { return db.Update(func(txn *badger.Txn) error { return txn.Set(key, value) }) } -func Get(db *badger.DB, key []byte) (value []byte, err error) { +func getDB(db *badger.DB, key []byte) (value []byte, err error) { err = db.View(func(txn *badger.Txn) error { item, err := txn.Get(key) if err != nil { @@ -35,7 +32,7 @@ func Get(db *badger.DB, key []byte) (value []byte, err error) { return } -func GetAndCopy(txn *badger.Txn, key []byte) (value []byte, err error) { +func getTxn(txn *badger.Txn, key []byte) (value []byte, err error) { item, err := txn.Get(key) if err != nil { return diff --git a/client/storage/liststorage.go b/client/storage/liststorage.go index edb9a17d..bf68b602 100644 --- a/client/storage/liststorage.go +++ b/client/storage/liststorage.go @@ -3,7 +3,6 @@ package storage import ( "context" "errors" - provider "github.com/anytypeio/go-anytype-infrastructure-experiments/client/badgerprovider" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclrecordproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage" "github.com/dgraph-io/badger/v3" @@ -20,13 +19,13 @@ type listStorage struct { func newListStorage(spaceId string, db *badger.DB, txn *badger.Txn) (ls storage.ListStorage, err error) { keys := newACLKeys(spaceId) - rootId, err := provider.GetAndCopy(txn, keys.RootIdKey()) + rootId, err := getTxn(txn, keys.RootIdKey()) if err != nil { return } stringId := string(rootId) - value, err := provider.GetAndCopy(txn, keys.RawRecordKey(stringId)) + value, err := getTxn(txn, keys.RawRecordKey(stringId)) if err != nil { return } @@ -47,7 +46,7 @@ func newListStorage(spaceId string, db *badger.DB, txn *badger.Txn) (ls storage. func createListStorage(spaceId string, db *badger.DB, txn *badger.Txn, root *aclrecordproto.RawACLRecordWithId) (ls storage.ListStorage, err error) { keys := newACLKeys(spaceId) - _, err = provider.GetAndCopy(txn, keys.RootIdKey()) + _, err = getTxn(txn, keys.RootIdKey()) if err != badger.ErrKeyNotFound { if err == nil { return newListStorage(spaceId, db, txn) @@ -87,7 +86,7 @@ func (l *listStorage) Root() (*aclrecordproto.RawACLRecordWithId, error) { } func (l *listStorage) Head() (head string, err error) { - bytes, err := provider.Get(l.db, l.keys.HeadIdKey()) + bytes, err := getDB(l.db, l.keys.HeadIdKey()) if err != nil { return } @@ -96,7 +95,7 @@ func (l *listStorage) Head() (head string, err error) { } func (l *listStorage) GetRawRecord(ctx context.Context, id string) (raw *aclrecordproto.RawACLRecordWithId, err error) { - res, err := provider.Get(l.db, l.keys.RawRecordKey(id)) + res, err := getDB(l.db, l.keys.RawRecordKey(id)) if err != nil { if err == badger.ErrKeyNotFound { err = storage.ErrUnknownRecord @@ -111,6 +110,10 @@ func (l *listStorage) GetRawRecord(ctx context.Context, id string) (raw *aclreco return } -func (l *listStorage) AddRawRecord(ctx context.Context, rec *aclrecordproto.RawACLRecordWithId) error { - return provider.Put(l.db, []byte(rec.Id), rec.Payload) +func (l *listStorage) SetHead(headId string) (err error) { + return putDB(l.db, l.keys.HeadIdKey(), []byte(headId)) +} + +func (l *listStorage) AddRawRecord(ctx context.Context, rec *aclrecordproto.RawACLRecordWithId) error { + return putDB(l.db, l.keys.RawRecordKey(rec.Id), rec.Payload) } diff --git a/client/storage/spacestorage.go b/client/storage/spacestorage.go index 5fb03f72..e05efa99 100644 --- a/client/storage/spacestorage.go +++ b/client/storage/spacestorage.go @@ -1,7 +1,6 @@ package storage import ( - provider "github.com/anytypeio/go-anytype-infrastructure-experiments/client/badgerprovider" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" spacestorage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage" @@ -21,7 +20,7 @@ type spaceStorage struct { func newSpaceStorage(objDb *badger.DB, spaceId string) (store spacestorage.SpaceStorage, err error) { keys := newSpaceKeys(spaceId) err = objDb.View(func(txn *badger.Txn) error { - header, err := provider.GetAndCopy(txn, keys.HeaderKey()) + header, err := getTxn(txn, keys.HeaderKey()) if err != nil { return err } @@ -51,7 +50,7 @@ func newSpaceStorage(objDb *badger.DB, spaceId string) (store spacestorage.Space func createSpaceStorage(db *badger.DB, payload spacestorage.SpaceStorageCreatePayload) (store spacestorage.SpaceStorage, err error) { keys := newSpaceKeys(payload.SpaceHeaderWithId.Id) - if provider.Has(db, keys.HeaderKey()) { + if hasDB(db, keys.HeaderKey()) { err = spacesyncproto.ErrSpaceExists return } @@ -78,6 +77,10 @@ func createSpaceStorage(db *badger.DB, payload spacestorage.SpaceStorageCreatePa return } +func (s *spaceStorage) ID() (string, error) { + return s.spaceId, nil +} + func (s *spaceStorage) TreeStorage(id string) (storage.TreeStorage, error) { return newTreeStorage(s.objDb, s.spaceId, id) } diff --git a/client/storage/treestorage.go b/client/storage/treestorage.go index aea492ac..39fbe8e2 100644 --- a/client/storage/treestorage.go +++ b/client/storage/treestorage.go @@ -2,7 +2,6 @@ package storage import ( "context" - provider "github.com/anytypeio/go-anytype-infrastructure-experiments/client/badgerprovider" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treechangeproto" "github.com/dgraph-io/badger/v3" @@ -23,7 +22,7 @@ func newTreeStorage(db *badger.DB, spaceId, treeId string) (ts storage.TreeStora return err } - root, err := provider.GetAndCopy(txn, keys.RawChangeKey(treeId)) + root, err := getTxn(txn, keys.RawChangeKey(treeId)) if err != nil { return err } @@ -46,7 +45,7 @@ func newTreeStorage(db *badger.DB, spaceId, treeId string) (ts storage.TreeStora func createTreeStorage(db *badger.DB, spaceId string, payload storage.TreeStorageCreatePayload) (ts storage.TreeStorage, err error) { keys := newTreeKeys(spaceId, payload.TreeId) - if provider.Has(db, keys.RootIdKey()) { + if hasDB(db, keys.RootIdKey()) { err = storage.ErrTreeExists return } @@ -95,7 +94,7 @@ func (t *treeStorage) Root() (raw *treechangeproto.RawTreeChangeWithId, err erro } func (t *treeStorage) Heads() (heads []string, err error) { - headsBytes, err := provider.Get(t.db, t.keys.HeadsKey()) + headsBytes, err := getDB(t.db, t.keys.HeadsKey()) if err != nil { if err == badger.ErrKeyNotFound { err = storage.ErrUnknownTreeId @@ -108,15 +107,15 @@ func (t *treeStorage) Heads() (heads []string, err error) { func (t *treeStorage) SetHeads(heads []string) (err error) { payload := storage.CreateHeadsPayload(heads) - return provider.Put(t.db, t.keys.HeadsKey(), payload) + return putDB(t.db, t.keys.HeadsKey(), payload) } func (t *treeStorage) AddRawChange(change *treechangeproto.RawTreeChangeWithId) (err error) { - return provider.Put(t.db, t.keys.RawChangeKey(change.Id), change.RawChange) + return putDB(t.db, t.keys.RawChangeKey(change.Id), change.RawChange) } func (t *treeStorage) GetRawChange(ctx context.Context, id string) (raw *treechangeproto.RawTreeChangeWithId, err error) { - res, err := provider.Get(t.db, t.keys.RawChangeKey(id)) + res, err := getDB(t.db, t.keys.RawChangeKey(id)) if err != nil { if err == badger.ErrKeyNotFound { err = storage.ErrUnknownTreeId @@ -132,5 +131,5 @@ func (t *treeStorage) GetRawChange(ctx context.Context, id string) (raw *treecha } func (t *treeStorage) HasChange(ctx context.Context, id string) (bool, error) { - return provider.Has(t.db, t.keys.RawChangeKey(id)), nil + return hasDB(t.db, t.keys.RawChangeKey(id)), nil } diff --git a/common/commonspace/service.go b/common/commonspace/service.go index c7c27081..2b5f2404 100644 --- a/common/commonspace/service.go +++ b/common/commonspace/service.go @@ -22,8 +22,8 @@ func New() Service { } type Service interface { - DeriveSpace(ctx context.Context, payload SpaceDerivePayload) (Space, error) - CreateSpace(ctx context.Context, payload SpaceCreatePayload) (Space, error) + DeriveSpace(ctx context.Context, payload SpaceDerivePayload) (string, error) + CreateSpace(ctx context.Context, payload SpaceCreatePayload) (string, error) GetSpace(ctx context.Context, id string) (sp Space, err error) app.Component } @@ -51,32 +51,32 @@ func (s *service) Name() (name string) { func (s *service) CreateSpace( ctx context.Context, - payload SpaceCreatePayload) (sp Space, err error) { + payload SpaceCreatePayload) (id string, err error) { storageCreate, err := storagePayloadForSpaceCreate(payload) if err != nil { return } - _, err = s.storageProvider.CreateSpaceStorage(storageCreate) + store, err := s.storageProvider.CreateSpaceStorage(storageCreate) if err != nil { return } - return s.GetSpace(ctx, storageCreate.SpaceHeaderWithId.GetId()) + return store.ID() } func (s *service) DeriveSpace( ctx context.Context, - payload SpaceDerivePayload) (sp Space, err error) { + payload SpaceDerivePayload) (id string, err error) { storageCreate, err := storagePayloadForSpaceDerive(payload) if err != nil { return } - _, err = s.storageProvider.CreateSpaceStorage(storageCreate) + store, err := s.storageProvider.CreateSpaceStorage(storageCreate) if err != nil { return } - return s.GetSpace(ctx, storageCreate.SpaceHeaderWithId.GetId()) + return store.ID() } func (s *service) GetSpace(ctx context.Context, id string) (Space, error) { diff --git a/common/commonspace/space.go b/common/commonspace/space.go index aa255f51..fca752ab 100644 --- a/common/commonspace/space.go +++ b/common/commonspace/space.go @@ -19,10 +19,15 @@ import ( ) type SpaceCreatePayload struct { - SigningKey signingkey.PrivKey - EncryptionKey encryptionkey.PrivKey - SpaceType string - ReadKey []byte + // SigningKey is the signing key of the owner + SigningKey signingkey.PrivKey + // EncryptionKey is the encryption key of the owner + EncryptionKey encryptionkey.PrivKey + // SpaceType is an arbitrary string + SpaceType string + // ReadKey is a first symmetric encryption key for a space + ReadKey []byte + // ReplicationKey is a key which is to be used to determine the node where the space should be held ReplicationKey uint64 } diff --git a/common/commonspace/storage/mock_storage/mock_storage.go b/common/commonspace/storage/mock_storage/mock_storage.go index 4cca0580..d1fd5934 100644 --- a/common/commonspace/storage/mock_storage/mock_storage.go +++ b/common/commonspace/storage/mock_storage/mock_storage.go @@ -162,6 +162,21 @@ func (mr *MockSpaceStorageMockRecorder) CreateTreeStorage(arg0 interface{}) *gom return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateTreeStorage", reflect.TypeOf((*MockSpaceStorage)(nil).CreateTreeStorage), arg0) } +// ID mocks base method. +func (m *MockSpaceStorage) ID() (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ID") + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ID indicates an expected call of ID. +func (mr *MockSpaceStorageMockRecorder) ID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockSpaceStorage)(nil).ID)) +} + // SpaceHeader mocks base method. func (m *MockSpaceStorage) SpaceHeader() (*spacesyncproto.RawSpaceHeaderWithId, error) { m.ctrl.T.Helper() diff --git a/common/commonspace/storage/storage.go b/common/commonspace/storage/storage.go index eada36f7..1189ede2 100644 --- a/common/commonspace/storage/storage.go +++ b/common/commonspace/storage/storage.go @@ -15,6 +15,7 @@ var ErrSpaceStorageExists = errors.New("space storage exists") var ErrSpaceStorageMissing = errors.New("space storage missing") type SpaceStorage interface { + storage.Storage storage.Provider ACLStorage() (storage.ListStorage, error) SpaceHeader() (*spacesyncproto.RawSpaceHeaderWithId, error) diff --git a/node/storage/liststorage.go b/node/storage/liststorage.go index 966f3fe0..142e175b 100644 --- a/node/storage/liststorage.go +++ b/node/storage/liststorage.go @@ -120,6 +120,10 @@ func (l *listStorage) GetRawRecord(ctx context.Context, id string) (raw *aclreco return } -func (l *listStorage) AddRawRecord(ctx context.Context, rec *aclrecordproto.RawACLRecordWithId) error { - return l.db.Put([]byte(rec.Id), rec.Payload) +func (l *listStorage) SetHead(headId string) (err error) { + return l.db.Put(l.keys.HeadIdKey(), []byte(headId)) +} + +func (l *listStorage) AddRawRecord(ctx context.Context, rec *aclrecordproto.RawACLRecordWithId) error { + return l.db.Put(l.keys.RawRecordKey(rec.Id), rec.Payload) } diff --git a/node/storage/spacestorage.go b/node/storage/spacestorage.go index 12b15534..3bf41085 100644 --- a/node/storage/spacestorage.go +++ b/node/storage/spacestorage.go @@ -15,6 +15,7 @@ var defPogrebOptions = &pogreb.Options{ } type spaceStorage struct { + spaceId string objDb *pogreb.DB keys spaceKeys aclStorage storage.ListStorage @@ -60,8 +61,9 @@ func newSpaceStorage(rootPath string, spaceId string) (store spacestorage.SpaceS } store = &spaceStorage{ - objDb: objDb, - keys: keys, + spaceId: spaceId, + objDb: objDb, + keys: keys, header: &spacesyncproto.RawSpaceHeaderWithId{ RawHeader: header, Id: spaceId, @@ -110,6 +112,7 @@ func createSpaceStorage(rootPath string, payload spacestorage.SpaceStorageCreate } store = &spaceStorage{ + spaceId: payload.SpaceHeaderWithId.Id, objDb: db, keys: keys, aclStorage: aclStorage, @@ -118,6 +121,10 @@ func createSpaceStorage(rootPath string, payload spacestorage.SpaceStorageCreate return } +func (s *spaceStorage) ID() (string, error) { + return s.spaceId, nil +} + func (s *spaceStorage) TreeStorage(id string) (storage.TreeStorage, error) { return newTreeStorage(s.objDb, id) } diff --git a/pkg/acl/storage/inmemory.go b/pkg/acl/storage/inmemory.go index b9948c3e..a992e84a 100644 --- a/pkg/acl/storage/inmemory.go +++ b/pkg/acl/storage/inmemory.go @@ -31,6 +31,10 @@ func (i *inMemoryACLListStorage) Root() (*aclrecordproto.RawACLRecordWithId, err return i.records[0], nil } +func (i *inMemoryACLListStorage) SetHead(headId string) error { + panic("implement me") +} + func (i *inMemoryACLListStorage) Head() (string, error) { i.RLock() defer i.RUnlock() diff --git a/pkg/acl/storage/liststorage.go b/pkg/acl/storage/liststorage.go index ad61a7fa..4ce5f814 100644 --- a/pkg/acl/storage/liststorage.go +++ b/pkg/acl/storage/liststorage.go @@ -15,6 +15,7 @@ type ListStorage interface { Storage Root() (*aclrecordproto.RawACLRecordWithId, error) Head() (string, error) + SetHead(headId string) error GetRawRecord(ctx context.Context, id string) (*aclrecordproto.RawACLRecordWithId, error) AddRawRecord(ctx context.Context, rec *aclrecordproto.RawACLRecordWithId) error diff --git a/pkg/acl/storage/mock_storage/mock_storage.go b/pkg/acl/storage/mock_storage/mock_storage.go index c4cf8800..0bfa22e8 100644 --- a/pkg/acl/storage/mock_storage/mock_storage.go +++ b/pkg/acl/storage/mock_storage/mock_storage.go @@ -110,6 +110,20 @@ func (mr *MockListStorageMockRecorder) Root() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Root", reflect.TypeOf((*MockListStorage)(nil).Root)) } +// SetHead mocks base method. +func (m *MockListStorage) SetHead(arg0 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetHead", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetHead indicates an expected call of SetHead. +func (mr *MockListStorageMockRecorder) SetHead(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetHead", reflect.TypeOf((*MockListStorage)(nil).SetHead), arg0) +} + // MockTreeStorage is a mock of TreeStorage interface. type MockTreeStorage struct { ctrl *gomock.Controller diff --git a/pkg/acl/testutils/acllistbuilder/liststoragebuilder.go b/pkg/acl/testutils/acllistbuilder/liststoragebuilder.go index 206550a5..7c0f4565 100644 --- a/pkg/acl/testutils/acllistbuilder/liststoragebuilder.go +++ b/pkg/acl/testutils/acllistbuilder/liststoragebuilder.go @@ -97,6 +97,10 @@ func (t *ACLListStorageBuilder) Head() (string, error) { return t.rawRoot.Id, nil } +func (t *ACLListStorageBuilder) SetHead(headId string) error { + panic("SetHead is not implemented") +} + func (t *ACLListStorageBuilder) Root() (*aclrecordproto.RawACLRecordWithId, error) { return t.rawRoot, nil }