Add exporter/viewer interfaces and empty methods, refactoring

This commit is contained in:
mcrakhman 2023-01-22 22:16:14 +01:00 committed by Mikhail Iudin
parent 13bd358bce
commit 88c4bc28f6
No known key found for this signature in database
GPG Key ID: FAAAA8BAABDFF1C0
14 changed files with 203 additions and 144 deletions

View File

@ -5,7 +5,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/anytypeio/any-sync/app/logger" "github.com/anytypeio/any-sync/app/logger"
aclrecordproto2 "github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto" aclrecordproto "github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto"
"github.com/anytypeio/any-sync/commonspace/object/keychain" "github.com/anytypeio/any-sync/commonspace/object/keychain"
"github.com/anytypeio/any-sync/util/keys" "github.com/anytypeio/any-sync/util/keys"
"github.com/anytypeio/any-sync/util/keys/asymmetric/encryptionkey" "github.com/anytypeio/any-sync/util/keys/asymmetric/encryptionkey"
@ -36,15 +36,15 @@ var (
type UserPermissionPair struct { type UserPermissionPair struct {
Identity string Identity string
Permission aclrecordproto2.AclUserPermissions Permission aclrecordproto.AclUserPermissions
} }
type AclState struct { type AclState struct {
id string id string
currentReadKeyHash uint64 currentReadKeyHash uint64
userReadKeys map[uint64]*symmetric.Key userReadKeys map[uint64]*symmetric.Key
userStates map[string]*aclrecordproto2.AclUserState userStates map[string]*aclrecordproto.AclUserState
userInvites map[string]*aclrecordproto2.AclUserInvite userInvites map[string]*aclrecordproto.AclUserInvite
encryptionKey encryptionkey.PrivKey encryptionKey encryptionkey.PrivKey
signingKey signingkey.PrivKey signingKey signingkey.PrivKey
totalReadKeys int totalReadKeys int
@ -70,8 +70,8 @@ func newAclStateWithKeys(
signingKey: signingKey, signingKey: signingKey,
encryptionKey: encryptionKey, encryptionKey: encryptionKey,
userReadKeys: make(map[uint64]*symmetric.Key), userReadKeys: make(map[uint64]*symmetric.Key),
userStates: make(map[string]*aclrecordproto2.AclUserState), userStates: make(map[string]*aclrecordproto.AclUserState),
userInvites: make(map[string]*aclrecordproto2.AclUserInvite), userInvites: make(map[string]*aclrecordproto.AclUserInvite),
permissionsAtRecord: make(map[string][]UserPermissionPair), permissionsAtRecord: make(map[string][]UserPermissionPair),
}, nil }, nil
} }
@ -80,8 +80,8 @@ func newAclState(id string) *AclState {
return &AclState{ return &AclState{
id: id, id: id,
userReadKeys: make(map[uint64]*symmetric.Key), userReadKeys: make(map[uint64]*symmetric.Key),
userStates: make(map[string]*aclrecordproto2.AclUserState), userStates: make(map[string]*aclrecordproto.AclUserState),
userInvites: make(map[string]*aclrecordproto2.AclUserInvite), userInvites: make(map[string]*aclrecordproto.AclUserInvite),
permissionsAtRecord: make(map[string][]UserPermissionPair), permissionsAtRecord: make(map[string][]UserPermissionPair),
} }
} }
@ -128,7 +128,7 @@ func (st *AclState) applyRecord(record *AclRecord) (err error) {
return return
} }
if record.Id == st.id { if record.Id == st.id {
root, ok := record.Model.(*aclrecordproto2.AclRoot) root, ok := record.Model.(*aclrecordproto.AclRoot)
if !ok { if !ok {
return ErrIncorrectRoot return ErrIncorrectRoot
} }
@ -137,14 +137,14 @@ func (st *AclState) applyRecord(record *AclRecord) (err error) {
return return
} }
st.permissionsAtRecord[record.Id] = []UserPermissionPair{ st.permissionsAtRecord[record.Id] = []UserPermissionPair{
{Identity: string(root.Identity), Permission: aclrecordproto2.AclUserPermissions_Admin}, {Identity: string(root.Identity), Permission: aclrecordproto.AclUserPermissions_Admin},
} }
return return
} }
aclData := &aclrecordproto2.AclData{} aclData := &aclrecordproto.AclData{}
if record.Model != nil { if record.Model != nil {
aclData = record.Model.(*aclrecordproto2.AclData) aclData = record.Model.(*aclrecordproto.AclData)
} else { } else {
err = proto.Unmarshal(record.Data, aclData) err = proto.Unmarshal(record.Data, aclData)
if err != nil { if err != nil {
@ -172,7 +172,7 @@ func (st *AclState) applyRecord(record *AclRecord) (err error) {
return return
} }
func (st *AclState) applyRoot(root *aclrecordproto2.AclRoot) (err error) { func (st *AclState) applyRoot(root *aclrecordproto.AclRoot) (err error) {
if st.signingKey != nil && st.encryptionKey != nil && st.identity == string(root.Identity) { if st.signingKey != nil && st.encryptionKey != nil && st.identity == string(root.Identity) {
err = st.saveReadKeyFromRoot(root) err = st.saveReadKeyFromRoot(root)
if err != nil { if err != nil {
@ -181,10 +181,10 @@ func (st *AclState) applyRoot(root *aclrecordproto2.AclRoot) (err error) {
} }
// adding user to the list // adding user to the list
userState := &aclrecordproto2.AclUserState{ userState := &aclrecordproto.AclUserState{
Identity: root.Identity, Identity: root.Identity,
EncryptionKey: root.EncryptionKey, EncryptionKey: root.EncryptionKey,
Permissions: aclrecordproto2.AclUserPermissions_Admin, Permissions: aclrecordproto.AclUserPermissions_Admin,
} }
st.currentReadKeyHash = root.CurrentReadKeyHash st.currentReadKeyHash = root.CurrentReadKeyHash
st.userStates[string(root.Identity)] = userState st.userStates[string(root.Identity)] = userState
@ -192,7 +192,7 @@ func (st *AclState) applyRoot(root *aclrecordproto2.AclRoot) (err error) {
return return
} }
func (st *AclState) saveReadKeyFromRoot(root *aclrecordproto2.AclRoot) (err error) { func (st *AclState) saveReadKeyFromRoot(root *aclrecordproto.AclRoot) (err error) {
var readKey *symmetric.Key var readKey *symmetric.Key
if len(root.GetDerivationScheme()) != 0 { if len(root.GetDerivationScheme()) != 0 {
var encPrivKey []byte var encPrivKey []byte
@ -206,7 +206,7 @@ func (st *AclState) saveReadKeyFromRoot(root *aclrecordproto2.AclRoot) (err erro
return return
} }
readKey, err = aclrecordproto2.AclReadKeyDerive(signPrivKey, encPrivKey) readKey, err = aclrecordproto.AclReadKeyDerive(signPrivKey, encPrivKey)
if err != nil { if err != nil {
return return
} }
@ -230,7 +230,7 @@ func (st *AclState) saveReadKeyFromRoot(root *aclrecordproto2.AclRoot) (err erro
return return
} }
func (st *AclState) applyChangeData(changeData *aclrecordproto2.AclData, hash uint64, identity []byte) (err error) { func (st *AclState) applyChangeData(changeData *aclrecordproto.AclData, hash uint64, identity []byte) (err error) {
defer func() { defer func() {
if err != nil { if err != nil {
return return
@ -248,7 +248,7 @@ func (st *AclState) applyChangeData(changeData *aclrecordproto2.AclData, hash ui
return return
} }
if !st.HasPermission(identity, aclrecordproto2.AclUserPermissions_Admin) { if !st.HasPermission(identity, aclrecordproto.AclUserPermissions_Admin) {
err = fmt.Errorf("user %s must have admin permissions", identity) err = fmt.Errorf("user %s must have admin permissions", identity)
return return
} }
@ -264,7 +264,7 @@ func (st *AclState) applyChangeData(changeData *aclrecordproto2.AclData, hash ui
return nil return nil
} }
func (st *AclState) applyChangeContent(ch *aclrecordproto2.AclContentValue) error { func (st *AclState) applyChangeContent(ch *aclrecordproto.AclContentValue) error {
switch { switch {
case ch.GetUserPermissionChange() != nil: case ch.GetUserPermissionChange() != nil:
return st.applyUserPermissionChange(ch.GetUserPermissionChange()) return st.applyUserPermissionChange(ch.GetUserPermissionChange())
@ -281,7 +281,7 @@ func (st *AclState) applyChangeContent(ch *aclrecordproto2.AclContentValue) erro
} }
} }
func (st *AclState) applyUserPermissionChange(ch *aclrecordproto2.AclUserPermissionChange) error { func (st *AclState) applyUserPermissionChange(ch *aclrecordproto.AclUserPermissionChange) error {
chIdentity := string(ch.Identity) chIdentity := string(ch.Identity)
state, exists := st.userStates[chIdentity] state, exists := st.userStates[chIdentity]
if !exists { if !exists {
@ -292,12 +292,12 @@ func (st *AclState) applyUserPermissionChange(ch *aclrecordproto2.AclUserPermiss
return nil return nil
} }
func (st *AclState) applyUserInvite(ch *aclrecordproto2.AclUserInvite) error { func (st *AclState) applyUserInvite(ch *aclrecordproto.AclUserInvite) error {
st.userInvites[string(ch.AcceptPublicKey)] = ch st.userInvites[string(ch.AcceptPublicKey)] = ch
return nil return nil
} }
func (st *AclState) applyUserJoin(ch *aclrecordproto2.AclUserJoin) error { func (st *AclState) applyUserJoin(ch *aclrecordproto.AclUserJoin) error {
invite, exists := st.userInvites[string(ch.AcceptPubKey)] invite, exists := st.userInvites[string(ch.AcceptPubKey)]
if !exists { if !exists {
return fmt.Errorf("no such invite with such public key %s", keys.EncodeBytesToString(ch.AcceptPubKey)) return fmt.Errorf("no such invite with such public key %s", keys.EncodeBytesToString(ch.AcceptPubKey))
@ -336,7 +336,7 @@ func (st *AclState) applyUserJoin(ch *aclrecordproto2.AclUserJoin) error {
} }
// adding user to the list // adding user to the list
userState := &aclrecordproto2.AclUserState{ userState := &aclrecordproto.AclUserState{
Identity: ch.Identity, Identity: ch.Identity,
EncryptionKey: ch.EncryptionKey, EncryptionKey: ch.EncryptionKey,
Permissions: invite.Permissions, Permissions: invite.Permissions,
@ -345,13 +345,13 @@ func (st *AclState) applyUserJoin(ch *aclrecordproto2.AclUserJoin) error {
return nil return nil
} }
func (st *AclState) applyUserAdd(ch *aclrecordproto2.AclUserAdd) error { func (st *AclState) applyUserAdd(ch *aclrecordproto.AclUserAdd) error {
chIdentity := string(ch.Identity) chIdentity := string(ch.Identity)
if _, exists := st.userStates[chIdentity]; exists { if _, exists := st.userStates[chIdentity]; exists {
return ErrUserAlreadyExists return ErrUserAlreadyExists
} }
st.userStates[chIdentity] = &aclrecordproto2.AclUserState{ st.userStates[chIdentity] = &aclrecordproto.AclUserState{
Identity: ch.Identity, Identity: ch.Identity,
EncryptionKey: ch.EncryptionKey, EncryptionKey: ch.EncryptionKey,
Permissions: ch.Permissions, Permissions: ch.Permissions,
@ -371,7 +371,7 @@ func (st *AclState) applyUserAdd(ch *aclrecordproto2.AclUserAdd) error {
return nil return nil
} }
func (st *AclState) applyUserRemove(ch *aclrecordproto2.AclUserRemove) error { func (st *AclState) applyUserRemove(ch *aclrecordproto.AclUserRemove) error {
chIdentity := string(ch.Identity) chIdentity := string(ch.Identity)
if chIdentity == st.identity { if chIdentity == st.identity {
return ErrDocumentForbidden return ErrDocumentForbidden
@ -415,7 +415,7 @@ func (st *AclState) decryptReadKeyAndHash(msg []byte) (*symmetric.Key, uint64, e
return key, hasher.Sum64(), nil return key, hasher.Sum64(), nil
} }
func (st *AclState) HasPermission(identity []byte, permission aclrecordproto2.AclUserPermissions) bool { func (st *AclState) HasPermission(identity []byte, permission aclrecordproto.AclUserPermissions) bool {
state, exists := st.userStates[string(identity)] state, exists := st.userStates[string(identity)]
if !exists { if !exists {
return false return false
@ -424,22 +424,22 @@ func (st *AclState) HasPermission(identity []byte, permission aclrecordproto2.Ac
return state.Permissions == permission return state.Permissions == permission
} }
func (st *AclState) isUserJoin(data *aclrecordproto2.AclData) bool { func (st *AclState) isUserJoin(data *aclrecordproto.AclData) bool {
// if we have a UserJoin, then it should always be the first one applied // if we have a UserJoin, then it should always be the first one applied
return data.GetAclContent() != nil && data.GetAclContent()[0].GetUserJoin() != nil return data.GetAclContent() != nil && data.GetAclContent()[0].GetUserJoin() != nil
} }
func (st *AclState) isUserAdd(data *aclrecordproto2.AclData, identity []byte) bool { func (st *AclState) isUserAdd(data *aclrecordproto.AclData, identity []byte) bool {
// if we have a UserAdd, then it should always be the first one applied // if we have a UserAdd, then it should always be the first one applied
userAdd := data.GetAclContent()[0].GetUserAdd() userAdd := data.GetAclContent()[0].GetUserAdd()
return data.GetAclContent() != nil && userAdd != nil && bytes.Compare(userAdd.GetIdentity(), identity) == 0 return data.GetAclContent() != nil && userAdd != nil && bytes.Compare(userAdd.GetIdentity(), identity) == 0
} }
func (st *AclState) UserStates() map[string]*aclrecordproto2.AclUserState { func (st *AclState) UserStates() map[string]*aclrecordproto.AclUserState {
return st.userStates return st.userStates
} }
func (st *AclState) Invite(acceptPubKey []byte) (invite *aclrecordproto2.AclUserInvite, err error) { func (st *AclState) Invite(acceptPubKey []byte) (invite *aclrecordproto.AclUserInvite, err error) {
invite, exists := st.userInvites[string(acceptPubKey)] invite, exists := st.userInvites[string(acceptPubKey)]
if !exists { if !exists {
err = ErrNoSuchInvite err = ErrNoSuchInvite

View File

@ -13,6 +13,10 @@ var (
ErrUnknownRecord = errors.New("record doesn't exist") ErrUnknownRecord = errors.New("record doesn't exist")
) )
type Exporter interface {
ListStorage(root *aclrecordproto.RawAclRecordWithId) (ListStorage, error)
}
type ListStorage interface { type ListStorage interface {
Id() string Id() string
Root() (*aclrecordproto.RawAclRecordWithId, error) Root() (*aclrecordproto.RawAclRecordWithId, error)

View File

@ -0,0 +1,26 @@
package exporter
import (
"github.com/anytypeio/any-sync/commonspace/object/acl/liststorage"
"github.com/anytypeio/any-sync/commonspace/object/tree/objecttree"
"github.com/anytypeio/any-sync/commonspace/object/tree/treestorage"
)
type DataConverter interface {
Unmarshall(decrypted []byte) (any, error)
Convert(model any) (any, error)
}
type TreeExporterParams struct {
ListStorageExporter liststorage.Exporter
TreeStorageExporter treestorage.Exporter
DataConverter DataConverter
}
type TreeExporter interface {
ExportUnencrypted(tree objecttree.ReadableObjectTree) (err error)
}
func NewTreeExporter(params TreeExporterParams) TreeExporter {
return nil
}

View File

@ -0,0 +1,11 @@
package exporter
import (
"github.com/anytypeio/any-sync/commonspace/object/acl/liststorage"
"github.com/anytypeio/any-sync/commonspace/object/tree/objecttree"
"github.com/anytypeio/any-sync/commonspace/object/tree/treestorage"
)
func ViewObjectTree(listStorage liststorage.ListStorage, treeStorage treestorage.TreeStorage) (objecttree.ReadableObjectTree, error) {
return nil, nil
}

View File

@ -35,12 +35,31 @@ type InitialContent struct {
Timestamp int64 Timestamp int64
} }
type nonVerifiableChangeBuilder struct {
ChangeBuilder
}
func (c *nonVerifiableChangeBuilder) BuildRoot(payload InitialContent) (ch *Change, raw *treechangeproto.RawTreeChangeWithId, err error) {
return c.ChangeBuilder.BuildRoot(payload)
}
func (c *nonVerifiableChangeBuilder) Unmarshall(rawChange *treechangeproto.RawTreeChangeWithId, verify bool) (ch *Change, err error) {
return c.ChangeBuilder.Unmarshall(rawChange, false)
}
func (c *nonVerifiableChangeBuilder) Build(payload BuilderContent) (ch *Change, raw *treechangeproto.RawTreeChangeWithId, err error) {
return c.ChangeBuilder.Build(payload)
}
func (c *nonVerifiableChangeBuilder) Marshall(ch *Change) (raw *treechangeproto.RawTreeChangeWithId, err error) {
return c.ChangeBuilder.Marshall(ch)
}
type ChangeBuilder interface { type ChangeBuilder interface {
ConvertFromRaw(rawIdChange *treechangeproto.RawTreeChangeWithId, verify bool) (ch *Change, err error) Unmarshall(rawIdChange *treechangeproto.RawTreeChangeWithId, verify bool) (ch *Change, err error)
BuildContent(payload BuilderContent) (ch *Change, raw *treechangeproto.RawTreeChangeWithId, err error) Build(payload BuilderContent) (ch *Change, raw *treechangeproto.RawTreeChangeWithId, err error)
BuildInitialContent(payload InitialContent) (ch *Change, raw *treechangeproto.RawTreeChangeWithId, err error) BuildRoot(payload InitialContent) (ch *Change, raw *treechangeproto.RawTreeChangeWithId, err error)
BuildRaw(ch *Change) (*treechangeproto.RawTreeChangeWithId, error) Marshall(ch *Change) (*treechangeproto.RawTreeChangeWithId, error)
SetRootRawChange(rawIdChange *treechangeproto.RawTreeChangeWithId)
} }
type changeBuilder struct { type changeBuilder struct {
@ -52,7 +71,7 @@ func NewChangeBuilder(keys *keychain.Keychain, rootChange *treechangeproto.RawTr
return &changeBuilder{keys: keys, rootChange: rootChange} return &changeBuilder{keys: keys, rootChange: rootChange}
} }
func (c *changeBuilder) ConvertFromRaw(rawIdChange *treechangeproto.RawTreeChangeWithId, verify bool) (ch *Change, err error) { func (c *changeBuilder) Unmarshall(rawIdChange *treechangeproto.RawTreeChangeWithId, verify bool) (ch *Change, err error) {
if rawIdChange.GetRawChange() == nil { if rawIdChange.GetRawChange() == nil {
err = ErrEmptyChange err = ErrEmptyChange
return return
@ -101,7 +120,7 @@ func (c *changeBuilder) SetRootRawChange(rawIdChange *treechangeproto.RawTreeCha
c.rootChange = rawIdChange c.rootChange = rawIdChange
} }
func (c *changeBuilder) BuildInitialContent(payload InitialContent) (ch *Change, rawIdChange *treechangeproto.RawTreeChangeWithId, err error) { func (c *changeBuilder) BuildRoot(payload InitialContent) (ch *Change, rawIdChange *treechangeproto.RawTreeChangeWithId, err error) {
change := &treechangeproto.RootChange{ change := &treechangeproto.RootChange{
AclHeadId: payload.AclHeadId, AclHeadId: payload.AclHeadId,
Timestamp: payload.Timestamp, Timestamp: payload.Timestamp,
@ -145,7 +164,7 @@ func (c *changeBuilder) BuildInitialContent(payload InitialContent) (ch *Change,
return return
} }
func (c *changeBuilder) BuildContent(payload BuilderContent) (ch *Change, rawIdChange *treechangeproto.RawTreeChangeWithId, err error) { func (c *changeBuilder) Build(payload BuilderContent) (ch *Change, rawIdChange *treechangeproto.RawTreeChangeWithId, err error) {
change := &treechangeproto.TreeChange{ change := &treechangeproto.TreeChange{
TreeHeadIds: payload.TreeHeadIds, TreeHeadIds: payload.TreeHeadIds,
AclHeadId: payload.AclHeadId, AclHeadId: payload.AclHeadId,
@ -200,7 +219,7 @@ func (c *changeBuilder) BuildContent(payload BuilderContent) (ch *Change, rawIdC
return return
} }
func (c *changeBuilder) BuildRaw(ch *Change) (raw *treechangeproto.RawTreeChangeWithId, err error) { func (c *changeBuilder) Marshall(ch *Change) (raw *treechangeproto.RawTreeChangeWithId, err error) {
if ch.Id == c.rootChange.Id { if ch.Id == c.rootChange.Id {
return c.rootChange, nil return c.rootChange, nil
} }

View File

@ -6,7 +6,6 @@ import (
"errors" "errors"
"github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto" "github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto"
list "github.com/anytypeio/any-sync/commonspace/object/acl/list" list "github.com/anytypeio/any-sync/commonspace/object/acl/list"
"github.com/anytypeio/any-sync/commonspace/object/keychain"
"github.com/anytypeio/any-sync/commonspace/object/tree/treechangeproto" "github.com/anytypeio/any-sync/commonspace/object/tree/treechangeproto"
"github.com/anytypeio/any-sync/commonspace/object/tree/treestorage" "github.com/anytypeio/any-sync/commonspace/object/tree/treestorage"
"github.com/anytypeio/any-sync/util/keys/symmetric" "github.com/anytypeio/any-sync/util/keys/symmetric"
@ -102,33 +101,6 @@ type objectTree struct {
sync.RWMutex sync.RWMutex
} }
type objectTreeDeps struct {
changeBuilder ChangeBuilder
treeBuilder *treeBuilder
treeStorage treestorage.TreeStorage
validator ObjectTreeValidator
rawChangeLoader *rawChangeLoader
aclList list.AclList
}
func defaultObjectTreeDeps(
rootChange *treechangeproto.RawTreeChangeWithId,
treeStorage treestorage.TreeStorage,
aclList list.AclList) objectTreeDeps {
keychain := keychain.NewKeychain()
changeBuilder := NewChangeBuilder(keychain, rootChange)
treeBuilder := newTreeBuilder(treeStorage, changeBuilder)
return objectTreeDeps{
changeBuilder: changeBuilder,
treeBuilder: treeBuilder,
treeStorage: treeStorage,
validator: newTreeValidator(),
rawChangeLoader: newRawChangeLoader(treeStorage, changeBuilder),
aclList: aclList,
}
}
func (ot *objectTree) rebuildFromStorage(theirHeads []string, newChanges []*Change) (err error) { func (ot *objectTree) rebuildFromStorage(theirHeads []string, newChanges []*Change) (err error) {
ot.treeBuilder.Reset() ot.treeBuilder.Reset()
@ -179,7 +151,7 @@ func (ot *objectTree) AddContent(ctx context.Context, content SignableChangeCont
oldHeads := make([]string, 0, len(ot.tree.Heads())) oldHeads := make([]string, 0, len(ot.tree.Heads()))
oldHeads = append(oldHeads, ot.tree.Heads()...) oldHeads = append(oldHeads, ot.tree.Heads()...)
objChange, rawChange, err := ot.changeBuilder.BuildContent(payload) objChange, rawChange, err := ot.changeBuilder.Build(payload)
if content.IsSnapshot { if content.IsSnapshot {
// clearing tree, because we already saved everything in the last snapshot // clearing tree, because we already saved everything in the last snapshot
ot.tree = &Tree{} ot.tree = &Tree{}
@ -293,7 +265,7 @@ func (ot *objectTree) addRawChanges(ctx context.Context, changesPayload RawChang
if unAttached, exists := ot.tree.unAttached[ch.Id]; exists { if unAttached, exists := ot.tree.unAttached[ch.Id]; exists {
change = unAttached change = unAttached
} else { } else {
change, err = ot.changeBuilder.ConvertFromRaw(ch, true) change, err = ot.changeBuilder.Unmarshall(ch, true)
if err != nil { if err != nil {
return return
} }
@ -444,7 +416,7 @@ func (ot *objectTree) createAddResult(oldHeads []string, mode Mode, treeChangesA
// if we got some changes that we need to convert to raw // if we got some changes that we need to convert to raw
if _, exists := alreadyConverted[ch]; !exists { if _, exists := alreadyConverted[ch]; !exists {
var raw *treechangeproto.RawTreeChangeWithId var raw *treechangeproto.RawTreeChangeWithId
raw, err = ot.changeBuilder.BuildRaw(ch) raw, err = ot.changeBuilder.Marshall(ch)
if err != nil { if err != nil {
return return
} }

View File

@ -59,44 +59,10 @@ func (c *mockChangeCreator) createNewTreeStorage(treeId, aclHeadId string) trees
return treeStorage return treeStorage
} }
type mockChangeBuilder struct {
originalBuilder ChangeBuilder
}
func (c *mockChangeBuilder) BuildInitialContent(payload InitialContent) (ch *Change, raw *treechangeproto.RawTreeChangeWithId, err error) {
panic("implement me")
}
func (c *mockChangeBuilder) SetRootRawChange(rawIdChange *treechangeproto.RawTreeChangeWithId) {
c.originalBuilder.SetRootRawChange(rawIdChange)
}
func (c *mockChangeBuilder) ConvertFromRaw(rawChange *treechangeproto.RawTreeChangeWithId, verify bool) (ch *Change, err error) {
return c.originalBuilder.ConvertFromRaw(rawChange, false)
}
func (c *mockChangeBuilder) BuildContent(payload BuilderContent) (ch *Change, raw *treechangeproto.RawTreeChangeWithId, err error) {
panic("implement me")
}
func (c *mockChangeBuilder) BuildRaw(ch *Change) (raw *treechangeproto.RawTreeChangeWithId, err error) {
return c.originalBuilder.BuildRaw(ch)
}
type mockChangeValidator struct{}
func (m *mockChangeValidator) ValidateNewChanges(tree *Tree, aclList list.AclList, newChanges []*Change) error {
return nil
}
func (m *mockChangeValidator) ValidateFullTree(tree *Tree, aclList list.AclList) error {
return nil
}
type testTreeContext struct { type testTreeContext struct {
aclList list.AclList aclList list.AclList
treeStorage treestorage.TreeStorage treeStorage treestorage.TreeStorage
changeBuilder *mockChangeBuilder changeBuilder ChangeBuilder
changeCreator *mockChangeCreator changeCreator *mockChangeCreator
objTree ObjectTree objTree ObjectTree
} }
@ -115,15 +81,15 @@ func prepareTreeDeps(aclList list.AclList) (*mockChangeCreator, objectTreeDeps)
changeCreator := &mockChangeCreator{} changeCreator := &mockChangeCreator{}
treeStorage := changeCreator.createNewTreeStorage("0", aclList.Head().Id) treeStorage := changeCreator.createNewTreeStorage("0", aclList.Head().Id)
root, _ := treeStorage.Root() root, _ := treeStorage.Root()
changeBuilder := &mockChangeBuilder{ changeBuilder := &nonVerifiableChangeBuilder{
originalBuilder: NewChangeBuilder(nil, root), ChangeBuilder: NewChangeBuilder(nil, root),
} }
deps := objectTreeDeps{ deps := objectTreeDeps{
changeBuilder: changeBuilder, changeBuilder: changeBuilder,
treeBuilder: newTreeBuilder(treeStorage, changeBuilder), treeBuilder: newTreeBuilder(treeStorage, changeBuilder),
treeStorage: treeStorage, treeStorage: treeStorage,
rawChangeLoader: newRawChangeLoader(treeStorage, changeBuilder), rawChangeLoader: newRawChangeLoader(treeStorage, changeBuilder),
validator: &mockChangeValidator{}, validator: &noOpTreeValidator{},
aclList: aclList, aclList: aclList,
} }
return changeCreator, deps return changeCreator, deps
@ -133,15 +99,15 @@ func prepareTreeContext(t *testing.T, aclList list.AclList) testTreeContext {
changeCreator := &mockChangeCreator{} changeCreator := &mockChangeCreator{}
treeStorage := changeCreator.createNewTreeStorage("0", aclList.Head().Id) treeStorage := changeCreator.createNewTreeStorage("0", aclList.Head().Id)
root, _ := treeStorage.Root() root, _ := treeStorage.Root()
changeBuilder := &mockChangeBuilder{ changeBuilder := &nonVerifiableChangeBuilder{
originalBuilder: NewChangeBuilder(nil, root), ChangeBuilder: NewChangeBuilder(nil, root),
} }
deps := objectTreeDeps{ deps := objectTreeDeps{
changeBuilder: changeBuilder, changeBuilder: changeBuilder,
treeBuilder: newTreeBuilder(treeStorage, changeBuilder), treeBuilder: newTreeBuilder(treeStorage, changeBuilder),
treeStorage: treeStorage, treeStorage: treeStorage,
rawChangeLoader: newRawChangeLoader(treeStorage, changeBuilder), rawChangeLoader: newRawChangeLoader(treeStorage, changeBuilder),
validator: &mockChangeValidator{}, validator: &noOpTreeValidator{},
aclList: aclList, aclList: aclList,
} }

View File

@ -39,7 +39,7 @@ func (r *rawChangeLoader) LoadFromTree(t *Tree, breakpoints []string) ([]*treech
convert := func(chs []*Change) (rawChanges []*treechangeproto.RawTreeChangeWithId, err error) { convert := func(chs []*Change) (rawChanges []*treechangeproto.RawTreeChangeWithId, err error) {
for _, ch := range chs { for _, ch := range chs {
var raw *treechangeproto.RawTreeChangeWithId var raw *treechangeproto.RawTreeChangeWithId
raw, err = r.changeBuilder.BuildRaw(ch) raw, err = r.changeBuilder.Marshall(ch)
if err != nil { if err != nil {
return return
} }
@ -226,7 +226,7 @@ func (r *rawChangeLoader) loadEntry(id string) (entry rawCacheEntry, err error)
return return
} }
change, err := r.changeBuilder.ConvertFromRaw(rawChange, false) change, err := r.changeBuilder.Unmarshall(rawChange, false)
if err != nil { if err != nil {
return return
} }

View File

@ -1,16 +0,0 @@
package objecttree
import (
"github.com/anytypeio/any-sync/commonspace/object/acl/list"
"github.com/anytypeio/any-sync/commonspace/object/tree/treestorage"
)
func ValidateRawTree(payload treestorage.TreeStorageCreatePayload, aclList list.AclList) (err error) {
treeStorage, err := treestorage.NewInMemoryTreeStorage(payload.RootRawChange, payload.Heads, payload.Changes)
if err != nil {
return
}
_, err = BuildObjectTree(treeStorage, aclList)
return
}

View File

@ -154,7 +154,7 @@ func (tb *treeBuilder) loadChange(id string) (ch *Change, err error) {
return nil, err return nil, err
} }
ch, err = tb.builder.ConvertFromRaw(change, true) ch, err = tb.builder.Unmarshall(change, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -19,6 +19,56 @@ type ObjectTreeCreatePayload struct {
IsEncrypted bool IsEncrypted bool
} }
type HistoryTreeParams struct {
TreeStorage treestorage.TreeStorage
AclList list.AclList
BeforeId string
IncludeBeforeId bool
}
type objectTreeDeps struct {
changeBuilder ChangeBuilder
treeBuilder *treeBuilder
treeStorage treestorage.TreeStorage
validator ObjectTreeValidator
rawChangeLoader *rawChangeLoader
aclList list.AclList
}
func defaultObjectTreeDeps(
rootChange *treechangeproto.RawTreeChangeWithId,
treeStorage treestorage.TreeStorage,
aclList list.AclList) objectTreeDeps {
keychain := keychain.NewKeychain()
changeBuilder := NewChangeBuilder(keychain, rootChange)
treeBuilder := newTreeBuilder(treeStorage, changeBuilder)
return objectTreeDeps{
changeBuilder: changeBuilder,
treeBuilder: treeBuilder,
treeStorage: treeStorage,
validator: newTreeValidator(),
rawChangeLoader: newRawChangeLoader(treeStorage, changeBuilder),
aclList: aclList,
}
}
func nonVerifiableTreeDeps(
rootChange *treechangeproto.RawTreeChangeWithId,
treeStorage treestorage.TreeStorage,
aclList list.AclList) objectTreeDeps {
changeBuilder := &nonVerifiableChangeBuilder{NewChangeBuilder(nil, rootChange)}
treeBuilder := newTreeBuilder(treeStorage, changeBuilder)
return objectTreeDeps{
changeBuilder: changeBuilder,
treeBuilder: treeBuilder,
treeStorage: treeStorage,
validator: &noOpTreeValidator{},
rawChangeLoader: newRawChangeLoader(treeStorage, changeBuilder),
aclList: aclList,
}
}
func CreateObjectTreeRoot(payload ObjectTreeCreatePayload, aclList list.AclList) (root *treechangeproto.RawTreeChangeWithId, err error) { func CreateObjectTreeRoot(payload ObjectTreeCreatePayload, aclList list.AclList) (root *treechangeproto.RawTreeChangeWithId, err error) {
bytes := make([]byte, 32) bytes := make([]byte, 32)
_, err = rand.Read(bytes) _, err = rand.Read(bytes)
@ -41,6 +91,15 @@ func BuildObjectTree(treeStorage treestorage.TreeStorage, aclList list.AclList)
return buildObjectTree(deps) return buildObjectTree(deps)
} }
func BuildNonVerifiableTree(treeStorage treestorage.TreeStorage, aclList list.AclList) (ObjectTree, error) {
rootChange, err := treeStorage.Root()
if err != nil {
return nil, err
}
deps := nonVerifiableTreeDeps(rootChange, treeStorage, aclList)
return buildObjectTree(deps)
}
func BuildHistoryTree(params HistoryTreeParams) (HistoryTree, error) { func BuildHistoryTree(params HistoryTreeParams) (HistoryTree, error) {
rootChange, err := params.TreeStorage.Root() rootChange, err := params.TreeStorage.Root()
if err != nil { if err != nil {
@ -115,7 +174,7 @@ func createObjectTreeRoot(
Seed: seed, Seed: seed,
} }
_, root, err = NewChangeBuilder(keychain.NewKeychain(), nil).BuildInitialContent(cnt) _, root, err = NewChangeBuilder(keychain.NewKeychain(), nil).BuildRoot(cnt)
return return
} }
@ -146,7 +205,7 @@ func buildObjectTree(deps objectTreeDeps) (ObjectTree, error) {
} }
// verifying root // verifying root
header, err := objTree.changeBuilder.ConvertFromRaw(objTree.rawRoot, true) header, err := objTree.changeBuilder.Unmarshall(objTree.rawRoot, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -155,13 +214,6 @@ func buildObjectTree(deps objectTreeDeps) (ObjectTree, error) {
return objTree, nil return objTree, nil
} }
type HistoryTreeParams struct {
TreeStorage treestorage.TreeStorage
AclList list.AclList
BeforeId string
IncludeBeforeId bool
}
func buildHistoryTree(deps objectTreeDeps, params HistoryTreeParams) (ht HistoryTree, err error) { func buildHistoryTree(deps objectTreeDeps, params HistoryTreeParams) (ht HistoryTree, err error) {
objTree := &objectTree{ objTree := &objectTree{
treeStorage: deps.treeStorage, treeStorage: deps.treeStorage,
@ -188,7 +240,7 @@ func buildHistoryTree(deps objectTreeDeps, params HistoryTreeParams) (ht History
return nil, err return nil, err
} }
header, err := objTree.changeBuilder.ConvertFromRaw(objTree.rawRoot, false) header, err := objTree.changeBuilder.Unmarshall(objTree.rawRoot, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto" "github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto"
"github.com/anytypeio/any-sync/commonspace/object/acl/list" "github.com/anytypeio/any-sync/commonspace/object/acl/list"
"github.com/anytypeio/any-sync/commonspace/object/tree/treestorage"
) )
type ObjectTreeValidator interface { type ObjectTreeValidator interface {
@ -13,6 +14,16 @@ type ObjectTreeValidator interface {
ValidateNewChanges(tree *Tree, aclList list.AclList, newChanges []*Change) error ValidateNewChanges(tree *Tree, aclList list.AclList, newChanges []*Change) error
} }
type noOpTreeValidator struct{}
func (n *noOpTreeValidator) ValidateFullTree(tree *Tree, aclList list.AclList) error {
return nil
}
func (n *noOpTreeValidator) ValidateNewChanges(tree *Tree, aclList list.AclList, newChanges []*Change) error {
return nil
}
type objectTreeValidator struct{} type objectTreeValidator struct{}
func newTreeValidator() ObjectTreeValidator { func newTreeValidator() ObjectTreeValidator {
@ -75,3 +86,13 @@ func (v *objectTreeValidator) validateChange(tree *Tree, aclList list.AclList, c
} }
return return
} }
func ValidateRawTree(payload treestorage.TreeStorageCreatePayload, aclList list.AclList) (err error) {
treeStorage, err := treestorage.NewInMemoryTreeStorage(payload.RootRawChange, payload.Heads, payload.Changes)
if err != nil {
return
}
_, err = BuildObjectTree(treeStorage, aclList)
return
}

View File

@ -19,6 +19,10 @@ type TreeStorageCreatePayload struct {
Heads []string Heads []string
} }
type Exporter interface {
TreeStorage(root *treechangeproto.RawTreeChangeWithId) (TreeStorage, error)
}
type TreeStorageCreatorFunc = func(payload TreeStorageCreatePayload) (TreeStorage, error) type TreeStorageCreatorFunc = func(payload TreeStorageCreatePayload) (TreeStorage, error)
type TreeStorage interface { type TreeStorage interface {

View File

@ -95,7 +95,7 @@ func storagePayloadForSpaceCreate(payload SpaceCreatePayload) (storagePayload sp
return return
} }
_, settingsRoot, err := builder.BuildInitialContent(objecttree.InitialContent{ _, settingsRoot, err := builder.BuildRoot(objecttree.InitialContent{
AclHeadId: rawWithId.Id, AclHeadId: rawWithId.Id,
Identity: aclRoot.Identity, Identity: aclRoot.Identity,
SigningKey: payload.SigningKey, SigningKey: payload.SigningKey,
@ -196,7 +196,7 @@ func storagePayloadForSpaceDerive(payload SpaceDerivePayload) (storagePayload sp
} }
builder := objecttree.NewChangeBuilder(keychain.NewKeychain(), nil) builder := objecttree.NewChangeBuilder(keychain.NewKeychain(), nil)
_, settingsRoot, err := builder.BuildInitialContent(objecttree.InitialContent{ _, settingsRoot, err := builder.BuildRoot(objecttree.InitialContent{
AclHeadId: rawWithId.Id, AclHeadId: rawWithId.Id,
Identity: aclRoot.Identity, Identity: aclRoot.Identity,
SigningKey: payload.SigningKey, SigningKey: payload.SigningKey,