Add logic update and create logic
This commit is contained in:
parent
e6534e134b
commit
43797b1b84
@ -10,7 +10,6 @@ import (
|
|||||||
|
|
||||||
type aclStateBuilder struct {
|
type aclStateBuilder struct {
|
||||||
tree *Tree
|
tree *Tree
|
||||||
aclState *ACLState
|
|
||||||
identity string
|
identity string
|
||||||
key keys.EncryptionPrivKey
|
key keys.EncryptionPrivKey
|
||||||
decoder keys.SigningPubKeyDecoder
|
decoder keys.SigningPubKeyDecoder
|
||||||
@ -29,15 +28,28 @@ func newACLStateBuilder(decoder keys.SigningPubKeyDecoder, accountData *account.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sb *aclStateBuilder) build() (*ACLState, error) {
|
func (sb *aclStateBuilder) Init(tree *Tree) error {
|
||||||
state, _, err := sb.buildBefore("")
|
sb.tree = tree
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sb *aclStateBuilder) Build() (*ACLState, error) {
|
||||||
|
state, _, err := sb.BuildBefore("")
|
||||||
return state, err
|
return state, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sb *aclStateBuilder) init(tree *Tree) error {
|
// TODO: we can probably have only one state builder, because we can Build both at the same time
|
||||||
root := tree.Root()
|
func (sb *aclStateBuilder) BuildBefore(beforeId string) (*ACLState, bool, error) {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
startChange = sb.tree.root
|
||||||
|
foundId bool
|
||||||
|
idSeenMap = make(map[string][]*Change)
|
||||||
|
decreasedPermissions *decreasedPermissionsParameters
|
||||||
|
)
|
||||||
|
root := sb.tree.Root()
|
||||||
if !root.IsSnapshot {
|
if !root.IsSnapshot {
|
||||||
return fmt.Errorf("root should always be a snapshot")
|
return nil, false, fmt.Errorf("root should always be a snapshot")
|
||||||
}
|
}
|
||||||
|
|
||||||
snapshot := root.Content.GetAclData().GetAclSnapshot()
|
snapshot := root.Content.GetAclData().GetAclSnapshot()
|
||||||
@ -47,27 +59,13 @@ func (sb *aclStateBuilder) init(tree *Tree) error {
|
|||||||
sb.key,
|
sb.key,
|
||||||
sb.decoder)
|
sb.decoder)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not build ACLState from snapshot: %w", err)
|
return nil, false, fmt.Errorf("could not build ACLState from snapshot: %w", err)
|
||||||
}
|
|
||||||
sb.tree = tree
|
|
||||||
sb.aclState = state
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: we can probably have only one state builder, because we can build both at the same time
|
|
||||||
func (sb *aclStateBuilder) buildBefore(beforeId string) (*ACLState, bool, error) {
|
|
||||||
var (
|
|
||||||
err error
|
|
||||||
startChange = sb.tree.root
|
|
||||||
foundId bool
|
|
||||||
idSeenMap = make(map[string][]*Change)
|
|
||||||
decreasedPermissions *decreasedPermissionsParameters
|
|
||||||
)
|
|
||||||
idSeenMap[startChange.Content.Identity] = append(idSeenMap[startChange.Content.Identity], startChange)
|
idSeenMap[startChange.Content.Identity] = append(idSeenMap[startChange.Content.Identity], startChange)
|
||||||
|
|
||||||
if startChange.Content.GetChangesData() != nil {
|
if startChange.Content.GetChangesData() != nil {
|
||||||
key, exists := sb.aclState.userReadKeys[startChange.Content.CurrentReadKeyHash]
|
key, exists := state.userReadKeys[startChange.Content.CurrentReadKeyHash]
|
||||||
if !exists {
|
if !exists {
|
||||||
return nil, false, fmt.Errorf("no first snapshot")
|
return nil, false, fmt.Errorf("no first snapshot")
|
||||||
}
|
}
|
||||||
@ -79,7 +77,7 @@ func (sb *aclStateBuilder) buildBefore(beforeId string) (*ACLState, bool, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if beforeId == startChange.Id {
|
if beforeId == startChange.Id {
|
||||||
return sb.aclState, true, nil
|
return state, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
@ -101,13 +99,13 @@ func (sb *aclStateBuilder) buildBefore(beforeId string) (*ACLState, bool, error)
|
|||||||
|
|
||||||
idSeenMap[c.Content.Identity] = append(idSeenMap[c.Content.Identity], c)
|
idSeenMap[c.Content.Identity] = append(idSeenMap[c.Content.Identity], c)
|
||||||
if c.Content.GetAclData() != nil {
|
if c.Content.GetAclData() != nil {
|
||||||
err = sb.aclState.applyChange(c.Id, c.Content)
|
err = state.applyChange(c.Id, c.Content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we have some users who have less permissions now
|
// if we have some users who have less permissions now
|
||||||
users := sb.aclState.getPermissionDecreasedUsers(c.Content)
|
users := state.getPermissionDecreasedUsers(c.Content)
|
||||||
if len(users) > 0 {
|
if len(users) > 0 {
|
||||||
decreasedPermissions = &decreasedPermissionsParameters{
|
decreasedPermissions = &decreasedPermissionsParameters{
|
||||||
users: users,
|
users: users,
|
||||||
@ -118,14 +116,14 @@ func (sb *aclStateBuilder) buildBefore(beforeId string) (*ACLState, bool, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// the user can't make changes
|
// the user can't make changes
|
||||||
if !sb.aclState.hasPermission(c.Content.Identity, pb.ACLChange_Writer) && !sb.aclState.hasPermission(c.Content.Identity, pb.ACLChange_Admin) {
|
if !state.hasPermission(c.Content.Identity, pb.ACLChange_Writer) && !state.hasPermission(c.Content.Identity, pb.ACLChange_Admin) {
|
||||||
err = fmt.Errorf("user %s cannot make changes", c.Content.Identity)
|
err = fmt.Errorf("user %s cannot make changes", c.Content.Identity)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// decrypting contents on the fly
|
// decrypting contents on the fly
|
||||||
if c.Content.GetChangesData() != nil {
|
if c.Content.GetChangesData() != nil {
|
||||||
key, exists := sb.aclState.userReadKeys[c.Content.CurrentReadKeyHash]
|
key, exists := state.userReadKeys[c.Content.CurrentReadKeyHash]
|
||||||
if !exists {
|
if !exists {
|
||||||
err = fmt.Errorf("failed to find key with hash: %d", c.Content.CurrentReadKeyHash)
|
err = fmt.Errorf("failed to find key with hash: %d", c.Content.CurrentReadKeyHash)
|
||||||
return false
|
return false
|
||||||
@ -169,7 +167,7 @@ func (sb *aclStateBuilder) buildBefore(beforeId string) (*ACLState, bool, error)
|
|||||||
decreasedPermissions = nil
|
decreasedPermissions = nil
|
||||||
if removed {
|
if removed {
|
||||||
// starting from the beginning but with updated Tree
|
// starting from the beginning but with updated Tree
|
||||||
return sb.buildBefore(beforeId)
|
return sb.BuildBefore(beforeId)
|
||||||
}
|
}
|
||||||
} else if err == nil {
|
} else if err == nil {
|
||||||
// we can finish the acl state building process
|
// we can finish the acl state building process
|
||||||
@ -185,5 +183,5 @@ func (sb *aclStateBuilder) buildBefore(beforeId string) (*ACLState, bool, error)
|
|||||||
err = nil
|
err = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return sb.aclState, foundId, err
|
return state, foundId, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,8 +19,8 @@ type ACLContext struct {
|
|||||||
|
|
||||||
func createTreeFromThread(t thread.Thread, fromStart bool) (*Tree, error) {
|
func createTreeFromThread(t thread.Thread, fromStart bool) (*Tree, error) {
|
||||||
treeBuilder := newTreeBuilder(t, keys.NewEd25519Decoder())
|
treeBuilder := newTreeBuilder(t, keys.NewEd25519Decoder())
|
||||||
treeBuilder.init()
|
treeBuilder.Init()
|
||||||
return treeBuilder.build(fromStart)
|
return treeBuilder.Build(fromStart)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createACLStateFromThread(
|
func createACLStateFromThread(
|
||||||
@ -40,16 +40,16 @@ func createACLStateFromThread(
|
|||||||
}
|
}
|
||||||
|
|
||||||
aclTreeBuilder := newACLTreeBuilder(t, decoder)
|
aclTreeBuilder := newACLTreeBuilder(t, decoder)
|
||||||
aclTreeBuilder.init()
|
aclTreeBuilder.Init()
|
||||||
aclTree, err := aclTreeBuilder.build()
|
aclTree, err := aclTreeBuilder.Build()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !fromStart {
|
if !fromStart {
|
||||||
snapshotValidator := newSnapshotValidator(decoder, accountData)
|
snapshotValidator := newSnapshotValidator(decoder, accountData)
|
||||||
snapshotValidator.init(aclTree)
|
snapshotValidator.Init(aclTree)
|
||||||
valid, err := snapshotValidator.validateSnapshot(tree.root)
|
valid, err := snapshotValidator.ValidateSnapshot(tree.root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -60,12 +60,12 @@ func createACLStateFromThread(
|
|||||||
}
|
}
|
||||||
|
|
||||||
aclBuilder := newACLStateBuilder(decoder, accountData)
|
aclBuilder := newACLStateBuilder(decoder, accountData)
|
||||||
err = aclBuilder.init(tree)
|
err = aclBuilder.Init(tree)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
aclState, err := aclBuilder.build()
|
aclState, err := aclBuilder.Build()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -88,7 +88,7 @@ func TestACLStateBuilder_UserJoinBuild(t *testing.T) {
|
|||||||
keys.NewEd25519Decoder(),
|
keys.NewEd25519Decoder(),
|
||||||
false)
|
false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("should build acl ACLState without err: %v", err)
|
t.Fatalf("should Build acl ACLState without err: %v", err)
|
||||||
}
|
}
|
||||||
aclState := ctx.ACLState
|
aclState := ctx.ACLState
|
||||||
//fmt.Println(ctx.Tree.Graph())
|
//fmt.Println(ctx.Tree.Graph())
|
||||||
@ -122,7 +122,7 @@ func TestACLStateBuilder_UserRemoveBuild(t *testing.T) {
|
|||||||
keys.NewEd25519Decoder(),
|
keys.NewEd25519Decoder(),
|
||||||
false)
|
false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("should build acl ACLState without err: %v", err)
|
t.Fatalf("should Build acl ACLState without err: %v", err)
|
||||||
}
|
}
|
||||||
aclState := ctx.ACLState
|
aclState := ctx.ACLState
|
||||||
//fmt.Println(ctx.Tree.Graph())
|
//fmt.Println(ctx.Tree.Graph())
|
||||||
@ -152,7 +152,7 @@ func TestACLStateBuilder_UserRemoveBeforeBuild(t *testing.T) {
|
|||||||
keys.NewEd25519Decoder(),
|
keys.NewEd25519Decoder(),
|
||||||
false)
|
false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("should build acl ACLState without err: %v", err)
|
t.Fatalf("should Build acl ACLState without err: %v", err)
|
||||||
}
|
}
|
||||||
aclState := ctx.ACLState
|
aclState := ctx.ACLState
|
||||||
//fmt.Println(ctx.Tree.Graph())
|
//fmt.Println(ctx.Tree.Graph())
|
||||||
@ -183,7 +183,7 @@ func TestACLStateBuilder_InvalidSnapshotBuild(t *testing.T) {
|
|||||||
keys.NewEd25519Decoder(),
|
keys.NewEd25519Decoder(),
|
||||||
false)
|
false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("should build acl ACLState without err: %v", err)
|
t.Fatalf("should Build acl ACLState without err: %v", err)
|
||||||
}
|
}
|
||||||
aclState := ctx.ACLState
|
aclState := ctx.ACLState
|
||||||
//fmt.Println(ctx.Tree.Graph())
|
//fmt.Println(ctx.Tree.Graph())
|
||||||
@ -213,7 +213,7 @@ func TestACLStateBuilder_ValidSnapshotBuild(t *testing.T) {
|
|||||||
keys.NewEd25519Decoder(),
|
keys.NewEd25519Decoder(),
|
||||||
false)
|
false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("should build acl ACLState without err: %v", err)
|
t.Fatalf("should Build acl ACLState without err: %v", err)
|
||||||
}
|
}
|
||||||
aclState := ctx.ACLState
|
aclState := ctx.ACLState
|
||||||
//fmt.Println(ctx.Tree.Graph())
|
//fmt.Println(ctx.Tree.Graph())
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import (
|
|||||||
"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/anytypeio/go-anytype-infrastructure-experiments/util/slice"
|
||||||
"github.com/gogo/protobuf/proto"
|
"github.com/gogo/protobuf/proto"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AddResultSummary int
|
type AddResultSummary int
|
||||||
@ -18,17 +19,17 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type AddResult struct {
|
type AddResult struct {
|
||||||
AttachedChanges []*Change
|
OldHeads []string
|
||||||
InvalidChanges []*Change
|
Heads []string
|
||||||
UnattachedChanges []*Change
|
// TODO: add summary for changes
|
||||||
|
|
||||||
Summary AddResultSummary
|
Summary AddResultSummary
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Change add change content to include ACLChangeBuilder
|
||||||
type ACLTree interface {
|
type ACLTree interface {
|
||||||
ACLState() *ACLState
|
ACLState() *ACLState
|
||||||
AddContent(changeContent *ChangeContent) (*Change, error)
|
AddContent(changeContent *ChangeContent) (*Change, error)
|
||||||
AddChanges(changes ...*Change) (AddResult, error) // TODO: Make change as interface
|
AddChanges(changes ...*Change) (AddResult, error)
|
||||||
Heads() []string
|
Heads() []string
|
||||||
Iterate(func(change *Change) bool)
|
Iterate(func(change *Change) bool)
|
||||||
IterateFrom(string, func(change *Change) bool)
|
IterateFrom(string, func(change *Change) bool)
|
||||||
@ -40,13 +41,15 @@ type aclTree struct {
|
|||||||
accountData *account.AccountData
|
accountData *account.AccountData
|
||||||
|
|
||||||
fullTree *Tree
|
fullTree *Tree
|
||||||
aclTree *Tree // this tree is built from start of the document
|
aclTree *Tree // TODO: right now we don't use it, we can probably have only local var for now. This tree is built from start of the document
|
||||||
aclState *ACLState
|
aclState *ACLState
|
||||||
|
|
||||||
treeBuilder *treeBuilder
|
treeBuilder *treeBuilder
|
||||||
aclTreeBuilder *aclTreeBuilder
|
aclTreeBuilder *aclTreeBuilder
|
||||||
aclStateBuilder *aclStateBuilder
|
aclStateBuilder *aclStateBuilder
|
||||||
snapshotValidator *snapshotValidator
|
snapshotValidator *snapshotValidator
|
||||||
|
|
||||||
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func BuildACLTree(t thread.Thread, acc *account.AccountData) (ACLTree, error) {
|
func BuildACLTree(t thread.Thread, acc *account.AccountData) (ACLTree, error) {
|
||||||
@ -74,14 +77,15 @@ func BuildACLTree(t thread.Thread, acc *account.AccountData) (ACLTree, error) {
|
|||||||
return aclTree, nil
|
return aclTree, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: this is not used for now, in future we should think about not making full tree rebuild
|
||||||
func (a *aclTree) rebuildFromTree(validateSnapshot bool) (err error) {
|
func (a *aclTree) rebuildFromTree(validateSnapshot bool) (err error) {
|
||||||
if validateSnapshot {
|
if validateSnapshot {
|
||||||
err = a.snapshotValidator.init(a.aclTree)
|
err = a.snapshotValidator.Init(a.aclTree)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
valid, err := a.snapshotValidator.validateSnapshot(a.fullTree.root)
|
valid, err := a.snapshotValidator.ValidateSnapshot(a.fullTree.root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -90,12 +94,12 @@ func (a *aclTree) rebuildFromTree(validateSnapshot bool) (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = a.aclStateBuilder.init(a.fullTree)
|
err = a.aclStateBuilder.Init(a.fullTree)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
a.aclState, err = a.aclStateBuilder.build()
|
a.aclState, err = a.aclStateBuilder.Build()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -104,28 +108,28 @@ func (a *aclTree) rebuildFromTree(validateSnapshot bool) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *aclTree) rebuildFromThread(fromStart bool) error {
|
func (a *aclTree) rebuildFromThread(fromStart bool) error {
|
||||||
a.treeBuilder.init()
|
a.treeBuilder.Init()
|
||||||
a.aclTreeBuilder.init()
|
a.aclTreeBuilder.Init()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
a.fullTree, err = a.treeBuilder.build(fromStart)
|
a.fullTree, err = a.treeBuilder.Build(fromStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
a.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(a.aclTree)
|
err = a.snapshotValidator.Init(a.aclTree)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
valid, err := a.snapshotValidator.validateSnapshot(a.fullTree.root)
|
valid, err := a.snapshotValidator.ValidateSnapshot(a.fullTree.root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -133,12 +137,12 @@ func (a *aclTree) rebuildFromThread(fromStart bool) error {
|
|||||||
return a.rebuildFromThread(true)
|
return a.rebuildFromThread(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = a.aclStateBuilder.init(a.fullTree)
|
err = a.aclStateBuilder.Init(a.fullTree)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
a.aclState, err = a.aclStateBuilder.build()
|
a.aclState, err = a.aclStateBuilder.Build()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -181,6 +185,8 @@ func (a *aclTree) ACLState() *ACLState {
|
|||||||
|
|
||||||
func (a *aclTree) AddContent(changeContent *ChangeContent) (*Change, error) {
|
func (a *aclTree) AddContent(changeContent *ChangeContent) (*Change, error) {
|
||||||
// TODO: add snapshot creation logic
|
// TODO: add snapshot creation logic
|
||||||
|
a.Lock()
|
||||||
|
defer a.Unlock()
|
||||||
marshalled, err := changeContent.ChangesData.Marshal()
|
marshalled, err := changeContent.ChangesData.Marshal()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -239,40 +245,100 @@ func (a *aclTree) AddContent(changeContent *ChangeContent) (*Change, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *aclTree) AddChanges(changes ...*Change) (AddResult, error) {
|
func (a *aclTree) AddChanges(changes ...*Change) (AddResult, error) {
|
||||||
|
a.Lock()
|
||||||
|
defer a.Unlock()
|
||||||
|
// TODO: make proper error handling, because there are a lot of corner cases where this will break
|
||||||
var aclChanges []*Change
|
var aclChanges []*Change
|
||||||
|
var err error
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// removing attached or invalid orphans
|
||||||
|
var toRemove []string
|
||||||
|
|
||||||
|
for _, orphan := range a.thread.Orphans() {
|
||||||
|
if _, exists := a.fullTree.attached[orphan]; exists {
|
||||||
|
toRemove = append(toRemove, orphan)
|
||||||
|
}
|
||||||
|
if _, exists := a.fullTree.invalidChanges[orphan]; exists {
|
||||||
|
toRemove = append(toRemove, orphan)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a.thread.RemoveOrphans(toRemove...)
|
||||||
|
}()
|
||||||
|
|
||||||
for _, ch := range changes {
|
for _, ch := range changes {
|
||||||
if ch.IsACLChange() {
|
if ch.IsACLChange() {
|
||||||
aclChanges = append(aclChanges, ch)
|
aclChanges = append(aclChanges, ch)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
a.thread.A
|
err = a.thread.AddChange(ch)
|
||||||
|
if err != nil {
|
||||||
|
return AddResult{}, err
|
||||||
|
}
|
||||||
|
a.thread.AddOrphans(ch.Id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: understand the common snapshot problem
|
|
||||||
prevHeads := a.fullTree.Heads()
|
prevHeads := a.fullTree.Heads()
|
||||||
mode := a.fullTree.Add(changes...)
|
mode := a.fullTree.Add(changes...)
|
||||||
switch mode {
|
switch mode {
|
||||||
case Nothing:
|
case Nothing:
|
||||||
return AddResult{Summary: AddResultSummaryNothing}, nil
|
return AddResult{
|
||||||
|
OldHeads: prevHeads,
|
||||||
|
Heads: prevHeads,
|
||||||
|
Summary: AddResultSummaryNothing,
|
||||||
|
}, nil
|
||||||
|
|
||||||
case Rebuild:
|
case Rebuild:
|
||||||
res, err := d.Build()
|
err = a.rebuildFromThread(false)
|
||||||
return AddResult{Summary: Rebuild}, err
|
if err != nil {
|
||||||
|
return AddResult{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return AddResult{
|
||||||
|
OldHeads: prevHeads,
|
||||||
|
Heads: a.fullTree.Heads(),
|
||||||
|
Summary: AddResultSummaryRebuild,
|
||||||
|
}, nil
|
||||||
default:
|
default:
|
||||||
break
|
a.aclState, err = a.aclStateBuilder.Build()
|
||||||
|
if err != nil {
|
||||||
|
return AddResult{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return AddResult{
|
||||||
|
OldHeads: prevHeads,
|
||||||
|
Heads: a.fullTree.Heads(),
|
||||||
|
Summary: AddResultSummaryAppend,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *aclTree) Iterate(f func(change *Change) bool) {
|
func (a *aclTree) Iterate(f func(change *Change) bool) {
|
||||||
//TODO implement me
|
a.Lock()
|
||||||
panic("implement me")
|
defer a.Unlock()
|
||||||
|
a.fullTree.Iterate(a.fullTree.RootId(), f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *aclTree) IterateFrom(s string, f func(change *Change) bool) {
|
func (a *aclTree) IterateFrom(s string, f func(change *Change) bool) {
|
||||||
//TODO implement me
|
a.Lock()
|
||||||
panic("implement me")
|
defer a.Unlock()
|
||||||
|
a.fullTree.Iterate(s, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *aclTree) HasChange(s string) bool {
|
func (a *aclTree) HasChange(s string) bool {
|
||||||
//TODO implement me
|
a.Lock()
|
||||||
panic("implement me")
|
defer a.Unlock()
|
||||||
|
_, attachedExists := a.fullTree.attached[s]
|
||||||
|
_, unattachedExists := a.fullTree.unAttached[s]
|
||||||
|
_, invalidExists := a.fullTree.invalidChanges[s]
|
||||||
|
return attachedExists || unattachedExists || invalidExists
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *aclTree) Heads() []string {
|
||||||
|
a.Lock()
|
||||||
|
defer a.Unlock()
|
||||||
|
return a.fullTree.Heads()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,16 +30,19 @@ func newACLTreeBuilder(t thread.Thread, decoder keys.SigningPubKeyDecoder) *aclT
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tb *aclTreeBuilder) init() {
|
func (tb *aclTreeBuilder) Init() {
|
||||||
tb.cache = make(map[string]*Change)
|
tb.cache = make(map[string]*Change)
|
||||||
tb.identityKeys = make(map[string]keys.SigningPubKey)
|
tb.identityKeys = make(map[string]keys.SigningPubKey)
|
||||||
tb.tree = &Tree{}
|
tb.tree = &Tree{}
|
||||||
tb.changeLoader.init(tb.cache, tb.identityKeys)
|
tb.changeLoader.Init(tb.cache, tb.identityKeys)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tb *aclTreeBuilder) build() (*Tree, error) {
|
func (tb *aclTreeBuilder) Build() (*Tree, error) {
|
||||||
heads := tb.thread.PossibleHeads()
|
var headsAndOrphans []string
|
||||||
aclHeads, err := tb.getACLHeads(heads)
|
headsAndOrphans = append(headsAndOrphans, tb.thread.Orphans()...)
|
||||||
|
headsAndOrphans = append(headsAndOrphans, tb.thread.Heads()...)
|
||||||
|
aclHeads, err := tb.getACLHeads(headsAndOrphans)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,7 +30,7 @@ func newChangeLoader(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *changeLoader) init(cache map[string]*Change,
|
func (c *changeLoader) Init(cache map[string]*Change,
|
||||||
identityKeys map[string]keys.SigningPubKey) {
|
identityKeys map[string]keys.SigningPubKey) {
|
||||||
c.cache = cache
|
c.cache = cache
|
||||||
c.identityKeys = identityKeys
|
c.identityKeys = identityKeys
|
||||||
|
|||||||
@ -26,13 +26,13 @@ func newSnapshotValidator(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *snapshotValidator) init(aclTree *Tree) error {
|
func (s *snapshotValidator) Init(aclTree *Tree) error {
|
||||||
s.aclTree = aclTree
|
s.aclTree = aclTree
|
||||||
return s.stateBuilder.init(aclTree)
|
return s.stateBuilder.Init(aclTree)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *snapshotValidator) validateSnapshot(ch *Change) (bool, error) {
|
func (s *snapshotValidator) ValidateSnapshot(ch *Change) (bool, error) {
|
||||||
st, found, err := s.stateBuilder.buildBefore(ch.Id)
|
st, found, err := s.stateBuilder.BuildBefore(ch.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,27 +38,29 @@ func newTreeBuilder(t thread.Thread, decoder keys.SigningPubKeyDecoder) *treeBui
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tb *treeBuilder) init() {
|
func (tb *treeBuilder) Init() {
|
||||||
tb.cache = make(map[string]*Change)
|
tb.cache = make(map[string]*Change)
|
||||||
tb.identityKeys = make(map[string]keys.SigningPubKey)
|
tb.identityKeys = make(map[string]keys.SigningPubKey)
|
||||||
tb.tree = &Tree{}
|
tb.tree = &Tree{}
|
||||||
tb.changeLoader.init(tb.cache, tb.identityKeys)
|
tb.changeLoader.Init(tb.cache, tb.identityKeys)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tb *treeBuilder) build(fromStart bool) (*Tree, error) {
|
func (tb *treeBuilder) Build(fromStart bool) (*Tree, error) {
|
||||||
heads := tb.thread.PossibleHeads()
|
var headsAndOrphans []string
|
||||||
|
headsAndOrphans = append(headsAndOrphans, tb.thread.Orphans()...)
|
||||||
|
headsAndOrphans = append(headsAndOrphans, tb.thread.Heads()...)
|
||||||
|
|
||||||
if fromStart {
|
if fromStart {
|
||||||
if err := tb.buildTreeFromStart(heads); err != nil {
|
if err := tb.buildTreeFromStart(headsAndOrphans); err != nil {
|
||||||
return nil, fmt.Errorf("buildTree error: %v", err)
|
return nil, fmt.Errorf("buildTree error: %v", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
breakpoint, err := tb.findBreakpoint(heads)
|
breakpoint, err := tb.findBreakpoint(headsAndOrphans)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("findBreakpoint error: %v", err)
|
return nil, fmt.Errorf("findBreakpoint error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = tb.buildTree(heads, breakpoint); err != nil {
|
if err = tb.buildTree(headsAndOrphans, breakpoint); err != nil {
|
||||||
return nil, fmt.Errorf("buildTree error: %v", err)
|
return nil, fmt.Errorf("buildTree error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -109,7 +109,7 @@ func (t *ThreadBuilder) AddRawChange(change *thread.RawChange) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *ThreadBuilder) AddPossibleHead(head string) {
|
func (t *ThreadBuilder) AddOrphans(head string) {
|
||||||
t.maybeHeads = append(t.maybeHeads, head)
|
t.maybeHeads = append(t.maybeHeads, head)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,7 +140,7 @@ func (t *ThreadBuilder) AddChange(change aclchanges.Change) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *ThreadBuilder) PossibleHeads() []string {
|
func (t *ThreadBuilder) Orphans() []string {
|
||||||
return t.maybeHeads
|
return t.maybeHeads
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -11,13 +11,14 @@ type Thread interface {
|
|||||||
ID() string
|
ID() string
|
||||||
|
|
||||||
Heads() []string
|
Heads() []string
|
||||||
PossibleHeads() []string
|
Orphans() []string
|
||||||
SetHeads(heads []string)
|
SetHeads(heads []string)
|
||||||
SetPossibleHeads(heads []string)
|
RemoveOrphans(orphan ...string)
|
||||||
AddPossibleHead(head string)
|
AddOrphans(orphan ...string)
|
||||||
|
|
||||||
AddRawChange(change *RawChange) error
|
AddRawChange(change *RawChange) error
|
||||||
AddChange(change aclchanges.Change) error
|
AddChange(change aclchanges.Change) error
|
||||||
|
// TODO: have methods with raw changes also
|
||||||
GetChange(ctx context.Context, recordID string) (*RawChange, error)
|
GetChange(ctx context.Context, recordID string) (*RawChange, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user