Merge pull request #8 from anytypeio/middleware-compatibility
Middleware compatibility
This commit is contained in:
commit
38f831ab6b
@ -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
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
80
commonspace/object/tree/exporter/treeexporter.go
Normal file
80
commonspace/object/tree/exporter/treeexporter.go
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
package exporter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/anytypeio/any-sync/commonspace/object/acl/liststorage"
|
||||||
|
"github.com/anytypeio/any-sync/commonspace/object/keychain"
|
||||||
|
"github.com/anytypeio/any-sync/commonspace/object/tree/objecttree"
|
||||||
|
"github.com/anytypeio/any-sync/commonspace/object/tree/treechangeproto"
|
||||||
|
"github.com/anytypeio/any-sync/commonspace/object/tree/treestorage"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DataConverter interface {
|
||||||
|
Unmarshall(decrypted []byte) (any, error)
|
||||||
|
Marshall(model any) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type TreeExporterParams struct {
|
||||||
|
ListStorageExporter liststorage.Exporter
|
||||||
|
TreeStorageExporter treestorage.Exporter
|
||||||
|
DataConverter DataConverter
|
||||||
|
}
|
||||||
|
|
||||||
|
type TreeExporter interface {
|
||||||
|
ExportUnencrypted(tree objecttree.ReadableObjectTree) (err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type treeExporter struct {
|
||||||
|
listExporter liststorage.Exporter
|
||||||
|
treeExporter treestorage.Exporter
|
||||||
|
converter DataConverter
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTreeExporter(params TreeExporterParams) TreeExporter {
|
||||||
|
return &treeExporter{
|
||||||
|
listExporter: params.ListStorageExporter,
|
||||||
|
treeExporter: params.TreeStorageExporter,
|
||||||
|
converter: params.DataConverter,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *treeExporter) ExportUnencrypted(tree objecttree.ReadableObjectTree) (err error) {
|
||||||
|
lst := tree.AclList()
|
||||||
|
// this exports root which should be enough before we implement acls
|
||||||
|
_, err = t.listExporter.ListStorage(lst.Root())
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
treeStorage, err := t.treeExporter.TreeStorage(tree.Header())
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
changeBuilder := objecttree.NewChangeBuilder(keychain.NewKeychain(), tree.Header())
|
||||||
|
putStorage := func(change *objecttree.Change) (err error) {
|
||||||
|
var raw *treechangeproto.RawTreeChangeWithId
|
||||||
|
raw, err = changeBuilder.Marshall(change)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return treeStorage.AddRawChange(raw)
|
||||||
|
}
|
||||||
|
err = tree.IterateRoot(t.converter.Unmarshall, func(change *objecttree.Change) bool {
|
||||||
|
if change.Id == tree.Id() {
|
||||||
|
err = putStorage(change)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
var data []byte
|
||||||
|
data, err = t.converter.Marshall(change.Model)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// that means that change is unencrypted
|
||||||
|
change.ReadKeyHash = 0
|
||||||
|
change.Data = data
|
||||||
|
err = putStorage(change)
|
||||||
|
return err == nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return treeStorage.SetHeads(tree.Heads())
|
||||||
|
}
|
||||||
28
commonspace/object/tree/exporter/treeimport.go
Normal file
28
commonspace/object/tree/exporter/treeimport.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package exporter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/anytypeio/any-sync/commonspace/object/acl/list"
|
||||||
|
"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 TreeImportParams struct {
|
||||||
|
ListStorage liststorage.ListStorage
|
||||||
|
TreeStorage treestorage.TreeStorage
|
||||||
|
BeforeId string
|
||||||
|
IncludeBeforeId bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func ImportHistoryTree(params TreeImportParams) (tree objecttree.ReadableObjectTree, err error) {
|
||||||
|
aclList, err := list.BuildAclList(params.ListStorage)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return objecttree.BuildNonVerifiableHistoryTree(objecttree.HistoryTreeParams{
|
||||||
|
TreeStorage: params.TreeStorage,
|
||||||
|
AclList: aclList,
|
||||||
|
BeforeId: params.BeforeId,
|
||||||
|
IncludeBeforeId: params.IncludeBeforeId,
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import (
|
|||||||
context "context"
|
context "context"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
|
|
||||||
|
list "github.com/anytypeio/any-sync/commonspace/object/acl/list"
|
||||||
objecttree "github.com/anytypeio/any-sync/commonspace/object/tree/objecttree"
|
objecttree "github.com/anytypeio/any-sync/commonspace/object/tree/objecttree"
|
||||||
treechangeproto "github.com/anytypeio/any-sync/commonspace/object/tree/treechangeproto"
|
treechangeproto "github.com/anytypeio/any-sync/commonspace/object/tree/treechangeproto"
|
||||||
treestorage "github.com/anytypeio/any-sync/commonspace/object/tree/treestorage"
|
treestorage "github.com/anytypeio/any-sync/commonspace/object/tree/treestorage"
|
||||||
@ -37,6 +38,20 @@ func (m *MockObjectTree) EXPECT() *MockObjectTreeMockRecorder {
|
|||||||
return m.recorder
|
return m.recorder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AclList mocks base method.
|
||||||
|
func (m *MockObjectTree) AclList() list.AclList {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "AclList")
|
||||||
|
ret0, _ := ret[0].(list.AclList)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// AclList indicates an expected call of AclList.
|
||||||
|
func (mr *MockObjectTreeMockRecorder) AclList() *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AclList", reflect.TypeOf((*MockObjectTree)(nil).AclList))
|
||||||
|
}
|
||||||
|
|
||||||
// AddContent mocks base method.
|
// AddContent mocks base method.
|
||||||
func (m *MockObjectTree) AddContent(arg0 context.Context, arg1 objecttree.SignableChangeContent) (objecttree.AddResult, error) {
|
func (m *MockObjectTree) AddContent(arg0 context.Context, arg1 objecttree.SignableChangeContent) (objecttree.AddResult, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
@ -96,19 +111,19 @@ func (mr *MockObjectTreeMockRecorder) Close() *gomock.Call {
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockObjectTree)(nil).Close))
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockObjectTree)(nil).Close))
|
||||||
}
|
}
|
||||||
|
|
||||||
// DebugDump mocks base method.
|
// Debug mocks base method.
|
||||||
func (m *MockObjectTree) DebugDump(arg0 objecttree.DescriptionParser) (string, error) {
|
func (m *MockObjectTree) Debug(arg0 objecttree.DescriptionParser) (objecttree.DebugInfo, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "DebugDump", arg0)
|
ret := m.ctrl.Call(m, "Debug", arg0)
|
||||||
ret0, _ := ret[0].(string)
|
ret0, _ := ret[0].(objecttree.DebugInfo)
|
||||||
ret1, _ := ret[1].(error)
|
ret1, _ := ret[1].(error)
|
||||||
return ret0, ret1
|
return ret0, ret1
|
||||||
}
|
}
|
||||||
|
|
||||||
// DebugDump indicates an expected call of DebugDump.
|
// Debug indicates an expected call of Debug.
|
||||||
func (mr *MockObjectTreeMockRecorder) DebugDump(arg0 interface{}) *gomock.Call {
|
func (mr *MockObjectTreeMockRecorder) Debug(arg0 interface{}) *gomock.Call {
|
||||||
mr.mock.ctrl.T.Helper()
|
mr.mock.ctrl.T.Helper()
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DebugDump", reflect.TypeOf((*MockObjectTree)(nil).DebugDump), arg0)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Debug", reflect.TypeOf((*MockObjectTree)(nil).Debug), arg0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete mocks base method.
|
// Delete mocks base method.
|
||||||
|
|||||||
@ -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"
|
||||||
@ -53,10 +52,12 @@ type ReadableObjectTree interface {
|
|||||||
Heads() []string
|
Heads() []string
|
||||||
Root() *Change
|
Root() *Change
|
||||||
|
|
||||||
|
AclList() list.AclList
|
||||||
|
|
||||||
HasChanges(...string) bool
|
HasChanges(...string) bool
|
||||||
GetChange(string) (*Change, error)
|
GetChange(string) (*Change, error)
|
||||||
|
|
||||||
DebugDump(parser DescriptionParser) (string, error)
|
Debug(parser DescriptionParser) (DebugInfo, error)
|
||||||
IterateRoot(convert ChangeConvertFunc, iterate ChangeIterateFunc) error
|
IterateRoot(convert ChangeConvertFunc, iterate ChangeIterateFunc) error
|
||||||
IterateFrom(id string, convert ChangeConvertFunc, iterate ChangeIterateFunc) error
|
IterateFrom(id string, convert ChangeConvertFunc, iterate ChangeIterateFunc) error
|
||||||
}
|
}
|
||||||
@ -102,33 +103,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()
|
||||||
|
|
||||||
@ -150,6 +124,10 @@ func (ot *objectTree) Id() string {
|
|||||||
return ot.id
|
return ot.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ot *objectTree) AclList() list.AclList {
|
||||||
|
return ot.aclList
|
||||||
|
}
|
||||||
|
|
||||||
func (ot *objectTree) Header() *treechangeproto.RawTreeChangeWithId {
|
func (ot *objectTree) Header() *treechangeproto.RawTreeChangeWithId {
|
||||||
return ot.rawRoot
|
return ot.rawRoot
|
||||||
}
|
}
|
||||||
@ -179,7 +157,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 +271,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 +422,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
|
||||||
}
|
}
|
||||||
@ -637,6 +615,6 @@ func (ot *objectTree) validateTree(newChanges []*Change) error {
|
|||||||
return ot.validator.ValidateNewChanges(ot.tree, ot.aclList, newChanges)
|
return ot.validator.ValidateNewChanges(ot.tree, ot.aclList, newChanges)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ot *objectTree) DebugDump(parser DescriptionParser) (string, error) {
|
func (ot *objectTree) Debug(parser DescriptionParser) (DebugInfo, error) {
|
||||||
return ot.tree.Graph(parser)
|
return objectTreeDebug{}.debugInfo(ot, parser)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
25
commonspace/object/tree/objecttree/objecttreedebug.go
Normal file
25
commonspace/object/tree/objecttree/objecttreedebug.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package objecttree
|
||||||
|
|
||||||
|
type objectTreeDebug struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type DebugInfo struct {
|
||||||
|
TreeLen int
|
||||||
|
TreeString string
|
||||||
|
Graphviz string
|
||||||
|
Heads []string
|
||||||
|
SnapshotPath []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o objectTreeDebug) debugInfo(ot *objectTree, parser DescriptionParser) (di DebugInfo, err error) {
|
||||||
|
di = DebugInfo{}
|
||||||
|
di.Graphviz, err = ot.tree.Graph(parser)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
di.TreeString = ot.tree.String()
|
||||||
|
di.TreeLen = ot.tree.Len()
|
||||||
|
di.Heads = ot.Heads()
|
||||||
|
di.SnapshotPath = ot.SnapshotPath()
|
||||||
|
return
|
||||||
|
}
|
||||||
@ -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 BuildNonVerifiableHistoryTree(params HistoryTreeParams) (HistoryTree, error) {
|
||||||
|
rootChange, err := params.TreeStorage.Root()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
deps := nonVerifiableTreeDeps(rootChange, params.TreeStorage, params.AclList)
|
||||||
|
return buildHistoryTree(deps, params)
|
||||||
|
}
|
||||||
|
|
||||||
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,12 +174,13 @@ func createObjectTreeRoot(
|
|||||||
Seed: seed,
|
Seed: seed,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, root, err = NewChangeBuilder(keychain.NewKeychain(), nil).BuildInitialContent(cnt)
|
_, root, err = NewChangeBuilder(keychain.NewKeychain(), nil).BuildRoot(cnt)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildObjectTree(deps objectTreeDeps) (ObjectTree, error) {
|
func buildObjectTree(deps objectTreeDeps) (ObjectTree, error) {
|
||||||
objTree := &objectTree{
|
objTree := &objectTree{
|
||||||
|
id: deps.treeStorage.Id(),
|
||||||
treeStorage: deps.treeStorage,
|
treeStorage: deps.treeStorage,
|
||||||
treeBuilder: deps.treeBuilder,
|
treeBuilder: deps.treeBuilder,
|
||||||
validator: deps.validator,
|
validator: deps.validator,
|
||||||
@ -139,14 +199,13 @@ func buildObjectTree(deps objectTreeDeps) (ObjectTree, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
objTree.id = objTree.treeStorage.Id()
|
|
||||||
objTree.rawRoot, err = objTree.treeStorage.Root()
|
objTree.rawRoot, err = objTree.treeStorage.Root()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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,15 +214,9 @@ 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{
|
||||||
|
id: deps.treeStorage.Id(),
|
||||||
treeStorage: deps.treeStorage,
|
treeStorage: deps.treeStorage,
|
||||||
treeBuilder: deps.treeBuilder,
|
treeBuilder: deps.treeBuilder,
|
||||||
validator: deps.validator,
|
validator: deps.validator,
|
||||||
@ -188,7 +241,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
|
||||||
}
|
}
|
||||||
@ -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
|
||||||
|
}
|
||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
|
||||||
}
|
|
||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import (
|
|||||||
context "context"
|
context "context"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
|
|
||||||
|
list "github.com/anytypeio/any-sync/commonspace/object/acl/list"
|
||||||
objecttree "github.com/anytypeio/any-sync/commonspace/object/tree/objecttree"
|
objecttree "github.com/anytypeio/any-sync/commonspace/object/tree/objecttree"
|
||||||
updatelistener "github.com/anytypeio/any-sync/commonspace/object/tree/synctree/updatelistener"
|
updatelistener "github.com/anytypeio/any-sync/commonspace/object/tree/synctree/updatelistener"
|
||||||
treechangeproto "github.com/anytypeio/any-sync/commonspace/object/tree/treechangeproto"
|
treechangeproto "github.com/anytypeio/any-sync/commonspace/object/tree/treechangeproto"
|
||||||
@ -162,6 +163,20 @@ func (m *MockSyncTree) EXPECT() *MockSyncTreeMockRecorder {
|
|||||||
return m.recorder
|
return m.recorder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AclList mocks base method.
|
||||||
|
func (m *MockSyncTree) AclList() list.AclList {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "AclList")
|
||||||
|
ret0, _ := ret[0].(list.AclList)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// AclList indicates an expected call of AclList.
|
||||||
|
func (mr *MockSyncTreeMockRecorder) AclList() *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AclList", reflect.TypeOf((*MockSyncTree)(nil).AclList))
|
||||||
|
}
|
||||||
|
|
||||||
// AddContent mocks base method.
|
// AddContent mocks base method.
|
||||||
func (m *MockSyncTree) AddContent(arg0 context.Context, arg1 objecttree.SignableChangeContent) (objecttree.AddResult, error) {
|
func (m *MockSyncTree) AddContent(arg0 context.Context, arg1 objecttree.SignableChangeContent) (objecttree.AddResult, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
@ -221,19 +236,19 @@ func (mr *MockSyncTreeMockRecorder) Close() *gomock.Call {
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockSyncTree)(nil).Close))
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockSyncTree)(nil).Close))
|
||||||
}
|
}
|
||||||
|
|
||||||
// DebugDump mocks base method.
|
// Debug mocks base method.
|
||||||
func (m *MockSyncTree) DebugDump(arg0 objecttree.DescriptionParser) (string, error) {
|
func (m *MockSyncTree) Debug(arg0 objecttree.DescriptionParser) (objecttree.DebugInfo, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "DebugDump", arg0)
|
ret := m.ctrl.Call(m, "Debug", arg0)
|
||||||
ret0, _ := ret[0].(string)
|
ret0, _ := ret[0].(objecttree.DebugInfo)
|
||||||
ret1, _ := ret[1].(error)
|
ret1, _ := ret[1].(error)
|
||||||
return ret0, ret1
|
return ret0, ret1
|
||||||
}
|
}
|
||||||
|
|
||||||
// DebugDump indicates an expected call of DebugDump.
|
// Debug indicates an expected call of Debug.
|
||||||
func (mr *MockSyncTreeMockRecorder) DebugDump(arg0 interface{}) *gomock.Call {
|
func (mr *MockSyncTreeMockRecorder) Debug(arg0 interface{}) *gomock.Call {
|
||||||
mr.mock.ctrl.T.Helper()
|
mr.mock.ctrl.T.Helper()
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DebugDump", reflect.TypeOf((*MockSyncTree)(nil).DebugDump), arg0)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Debug", reflect.TypeOf((*MockSyncTree)(nil).Debug), arg0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete mocks base method.
|
// Delete mocks base method.
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/anytypeio/any-sync/commonspace/spacestorage/mock_spacestorage"
|
"github.com/anytypeio/any-sync/commonspace/spacestorage/mock_spacestorage"
|
||||||
"github.com/golang/mock/gomock"
|
"github.com/golang/mock/gomock"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -70,6 +71,7 @@ func TestDeletionState_GetQueued(t *testing.T) {
|
|||||||
fx.delState.queued["id2"] = struct{}{}
|
fx.delState.queued["id2"] = struct{}{}
|
||||||
|
|
||||||
queued := fx.delState.GetQueued()
|
queued := fx.delState.GetQueued()
|
||||||
|
sort.Strings(queued)
|
||||||
require.Equal(t, []string{"id1", "id2"}, queued)
|
require.Equal(t, []string{"id1", "id2"}, queued)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -35,8 +35,8 @@ type poolService struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *poolService) Init(a *app.App) (err error) {
|
func (p *poolService) Init(a *app.App) (err error) {
|
||||||
p.pool = &pool{}
|
|
||||||
p.dialer = a.MustComponent(dialer.CName).(dialer.Dialer)
|
p.dialer = a.MustComponent(dialer.CName).(dialer.Dialer)
|
||||||
|
p.pool = &pool{dialer: p.dialer}
|
||||||
if m := a.Component(metric.CName); m != nil {
|
if m := a.Component(metric.CName); m != nil {
|
||||||
p.metricReg = m.(metric.Metric).Registry()
|
p.metricReg = m.(metric.Metric).Registry()
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user