WIP ACLTree

This commit is contained in:
mcrakhman 2022-07-08 15:13:01 +02:00 committed by Mikhail Iudin
parent ed06aadd21
commit 8570c4e318
No known key found for this signature in database
GPG Key ID: FAAAA8BAABDFF1C0

View File

@ -2,8 +2,11 @@ package acltree
import ( import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/account" "github.com/anytypeio/go-anytype-infrastructure-experiments/account"
"github.com/anytypeio/go-anytype-infrastructure-experiments/aclchanges/pb"
"github.com/anytypeio/go-anytype-infrastructure-experiments/thread" "github.com/anytypeio/go-anytype-infrastructure-experiments/thread"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys" "github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/slice"
"github.com/gogo/protobuf/proto"
) )
type AddResultSummary int type AddResultSummary int
@ -37,6 +40,7 @@ type aclTree struct {
accountData *account.AccountData accountData *account.AccountData
fullTree *Tree fullTree *Tree
aclTree *Tree // this tree is built from start of the document
aclState *ACLState aclState *ACLState
treeBuilder *treeBuilder treeBuilder *treeBuilder
@ -70,9 +74,36 @@ func BuildACLTree(t thread.Thread, acc *account.AccountData) (ACLTree, error) {
return aclTree, nil return aclTree, nil
} }
func (a *aclTree) rebuildFromThread(fromStart bool) error { func (a *aclTree) rebuildFromTree(validateSnapshot bool) (err error) {
var aclTree *Tree if validateSnapshot {
err = a.snapshotValidator.init(a.aclTree)
if err != nil {
return err
}
valid, err := a.snapshotValidator.validateSnapshot(a.fullTree.root)
if err != nil {
return err
}
if !valid {
return a.rebuildFromThread(true)
}
}
err = a.aclStateBuilder.init(a.fullTree)
if err != nil {
return err
}
a.aclState, err = a.aclStateBuilder.build()
if err != nil {
return err
}
return nil
}
func (a *aclTree) rebuildFromThread(fromStart bool) error {
a.treeBuilder.init() a.treeBuilder.init()
a.aclTreeBuilder.init() a.aclTreeBuilder.init()
@ -83,13 +114,13 @@ func (a *aclTree) rebuildFromThread(fromStart bool) error {
} }
// TODO: remove this from context as this is used only to validate snapshot // TODO: remove this from context as this is used only to validate snapshot
aclTree, err = a.aclTreeBuilder.build() a.aclTree, err = a.aclTreeBuilder.build()
if err != nil { if err != nil {
return err return err
} }
if !fromStart { if !fromStart {
err = a.snapshotValidator.init(aclTree) err = a.snapshotValidator.init(a.aclTree)
if err != nil { if err != nil {
return err return err
} }
@ -115,19 +146,120 @@ func (a *aclTree) rebuildFromThread(fromStart bool) error {
return nil return nil
} }
// TODO: this should not be the responsibility of ACLTree, move it somewhere else after testing
func (a *aclTree) getACLHeads() []string {
var aclTreeHeads []string
for _, head := range a.fullTree.Heads() {
if slice.FindPos(aclTreeHeads, head) != -1 { // do not scan known heads
continue
}
precedingHeads := a.getPrecedingACLHeads(head)
for _, aclHead := range precedingHeads {
if slice.FindPos(aclTreeHeads, aclHead) != -1 {
continue
}
aclTreeHeads = append(aclTreeHeads, aclHead)
}
}
return aclTreeHeads
}
func (a *aclTree) getPrecedingACLHeads(head string) []string {
headChange := a.fullTree.attached[head]
if headChange.Content.GetAclData() != nil {
return []string{head}
} else {
return headChange.Content.AclHeadIds
}
}
func (a *aclTree) ACLState() *ACLState { func (a *aclTree) ACLState() *ACLState {
//TODO implement me return a.aclState
panic("implement me")
} }
func (a *aclTree) AddContent(changeContent *ChangeContent) (*Change, error) { func (a *aclTree) AddContent(changeContent *ChangeContent) (*Change, error) {
//TODO implement me // TODO: add snapshot creation logic
panic("implement me") marshalled, err := changeContent.ChangesData.Marshal()
if err != nil {
return nil, err
}
encrypted, err := a.aclState.userReadKeys[a.aclState.currentReadKeyHash].
Encrypt(marshalled)
if err != nil {
return nil, err
}
aclChange := &pb.ACLChange{
TreeHeadIds: a.fullTree.Heads(),
AclHeadIds: a.getACLHeads(),
SnapshotBaseId: a.fullTree.RootId(),
AclData: changeContent.ACLData,
ChangesData: encrypted,
CurrentReadKeyHash: a.aclState.currentReadKeyHash,
Timestamp: 0,
Identity: a.accountData.Identity,
}
// TODO: add CID creation logic based on content
ch := NewChange(changeContent.Id, aclChange)
ch.DecryptedDocumentChange = marshalled
fullMarshalledChange, err := proto.Marshal(aclChange)
if err != nil {
return nil, err
}
signature, err := a.accountData.SignKey.Sign(fullMarshalledChange)
if err != nil {
return nil, err
}
if aclChange.AclData != nil {
// we can apply change right away without going through builder, because
err = a.aclState.applyChange(changeContent.Id, aclChange)
if err != nil {
return nil, err
}
}
a.fullTree.AddFast(ch)
err = a.thread.AddChange(&thread.RawChange{
Payload: marshalled,
Signature: signature,
Id: changeContent.Id,
})
if err != nil {
return nil, err
}
a.thread.SetHeads([]string{ch.Id})
return a.fullTree.attached[changeContent.Id], nil
} }
func (a *aclTree) AddChanges(changes ...*Change) (AddResult, error) { func (a *aclTree) AddChanges(changes ...*Change) (AddResult, error) {
//TODO implement me var aclChanges []*Change
panic("implement me") for _, ch := range changes {
if ch.IsACLChange() {
aclChanges = append(aclChanges, ch)
break
}
}
// TODO: understand the common snapshot problem
prevHeads := a.fullTree.Heads()
prevRoot := a.
mode := a.fullTree.Add(changes...)
switch mode {
case acltree.Nothing:
return d.docContext.docState, UpdateResultNoAction, nil
case acltree.Rebuild:
res, err := d.Build()
return res, UpdateResultRebuild, err
default:
break
}
} }
func (a *aclTree) Heads() []string { func (a *aclTree) Heads() []string {