diff --git a/acltree/acltree.go b/acltree/acltree.go index 46191d4c..82aa688c 100644 --- a/acltree/acltree.go +++ b/acltree/acltree.go @@ -54,7 +54,7 @@ type aclTree struct { snapshotValidator *snapshotValidator changeBuilder *changeBuilder - sync.Mutex + sync.RWMutex } func BuildACLTree( @@ -86,6 +86,7 @@ func BuildACLTree( } aclTree.removeOrphans() t.SetHeads(aclTree.Heads()) + listener.Rebuild(aclTree) return aclTree, nil } @@ -183,13 +184,19 @@ func (a *aclTree) rebuildFromThread(fromStart bool) error { } func (a *aclTree) ACLState() *ACLState { + a.RLock() + defer a.RUnlock() return a.aclState } func (a *aclTree) AddContent(build func(builder ChangeBuilder) error) (*Change, error) { // TODO: add snapshot creation logic a.Lock() - defer a.Unlock() + defer func() { + a.Unlock() + // TODO: should this be called in a separate goroutine to prevent accidental cycles (tree->updater->tree) + a.updateListener.Update(a) + }() a.changeBuilder.Init(a.aclState, a.fullTree, a.accountData) err := build(a.changeBuilder) @@ -213,13 +220,11 @@ func (a *aclTree) AddContent(build func(builder ChangeBuilder) error) (*Change, } a.thread.SetHeads([]string{ch.Id}) - a.updateListener.Update(a) return ch, nil } 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 err error var mode Mode @@ -230,6 +235,7 @@ func (a *aclTree) AddChanges(changes ...*Change) (AddResult, error) { } a.removeOrphans() a.thread.SetHeads(a.fullTree.Heads()) + a.Unlock() switch mode { case Append: a.updateListener.Update(a) @@ -286,20 +292,20 @@ func (a *aclTree) AddChanges(changes ...*Change) (AddResult, error) { } func (a *aclTree) Iterate(f func(change *Change) bool) { - a.Lock() - defer a.Unlock() + a.RLock() + defer a.RUnlock() a.fullTree.Iterate(a.fullTree.RootId(), f) } func (a *aclTree) IterateFrom(s string, f func(change *Change) bool) { - a.Lock() - defer a.Unlock() + a.RLock() + defer a.RUnlock() a.fullTree.Iterate(s, f) } func (a *aclTree) HasChange(s string) bool { - a.Lock() - defer a.Unlock() + a.RLock() + defer a.RUnlock() _, attachedExists := a.fullTree.attached[s] _, unattachedExists := a.fullTree.unAttached[s] _, invalidExists := a.fullTree.invalidChanges[s] @@ -307,13 +313,13 @@ func (a *aclTree) HasChange(s string) bool { } func (a *aclTree) Heads() []string { - a.Lock() - defer a.Unlock() + a.RLock() + defer a.RUnlock() return a.fullTree.Heads() } func (a *aclTree) Root() *Change { - a.Lock() - defer a.Unlock() + a.RLock() + defer a.RUnlock() return a.fullTree.Root() } diff --git a/acltree/treebuilder.go b/acltree/treebuilder.go index 944a44e1..1a34a3ae 100644 --- a/acltree/treebuilder.go +++ b/acltree/treebuilder.go @@ -169,6 +169,9 @@ func (tb *treeBuilder) findBreakpoint(heads []string) (breakpoint string, err er return } shId := ch.SnapshotId + if ch.IsSnapshot { + shId = ch.Id + } if slice.FindPos(snapshotIds, shId) == -1 { snapshotIds = append(snapshotIds, shId) } diff --git a/plaintextdocument/document.go b/plaintextdocument/document.go index 653388f9..63c07bde 100644 --- a/plaintextdocument/document.go +++ b/plaintextdocument/document.go @@ -23,7 +23,10 @@ type plainTextDocument struct { } func (p *plainTextDocument) Text() string { - return p.state.Text + if p.state != nil { + return p.state.Text + } + return "" } func (p *plainTextDocument) AddText(text string) error { diff --git a/plaintextdocument/document_test.go b/plaintextdocument/document_test.go index 0532240e..af596e54 100644 --- a/plaintextdocument/document_test.go +++ b/plaintextdocument/document_test.go @@ -1,53 +1,48 @@ package plaintextdocument -// -//import ( -// "github.com/anytypeio/go-anytype-infrastructure-experiments/testutils/threadbuilder" -// "github.com/stretchr/testify/assert" -// "testing" -//) -// -//func TestDocument_Build(t *testing.T) { -// thread, err := threadbuilder.NewThreadBuilderWithTestName("threadbuilder/userjoinexample.yml") -// if err != nil { -// t.Fatal(err) -// } -// keychain := thread.GetKeychain() -// accountData := &AccountData{ -// Identity: keychain.GetIdentity("A"), -// EncKey: keychain.EncryptionKeys["A"], -// } -// doc := NewDocument(thread, NewPlainTextDocumentStateProvider(), accountData) -// res, err := doc.Build() -// if err != nil { -// t.Fatal(err) -// } -// -// st := res.(*DocumentState) -// assert.Equal(t, st.Text, "some text|first") -//} -// -//func TestDocument_Update(t *testing.T) { -// thread, err := threadbuilder.NewThreadBuilderWithTestName("threadbuilder/userjoinexample.yml") -// if err != nil { -// t.Fatal(err) -// } -// keychain := thread.GetKeychain() -// accountData := &AccountData{ -// Identity: keychain.GetIdentity("A"), -// EncKey: keychain.EncryptionKeys["A"], -// } -// doc := NewDocument(thread, NewPlainTextDocumentStateProvider(), accountData) -// res, err := doc.Build() -// if err != nil { -// t.Fatal(err) -// } -// -// st := res.(*DocumentState) -// assert.Equal(t, st.Text, "some text|first") -// -// rawChs := thread.GetUpdatedChanges() -// res, updateResult, err := doc.Update(rawChs...) -// assert.Equal(t, updateResult, UpdateResultAppend) -// assert.Equal(t, res.(*DocumentState).Text, "some text|first|second") -//} +import ( + "github.com/anytypeio/go-anytype-infrastructure-experiments/account" + "github.com/anytypeio/go-anytype-infrastructure-experiments/testutils/threadbuilder" + "github.com/anytypeio/go-anytype-infrastructure-experiments/thread" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestDocument_NewPlainTextDocument(t *testing.T) { + keychain := threadbuilder.NewKeychain() + keychain.AddSigningKey("A") + keychain.AddEncryptionKey("A") + data := &account.AccountData{ + Identity: keychain.GetIdentity("A"), + SignKey: keychain.SigningKeys["A"], + EncKey: keychain.EncryptionKeys["A"], + } + + doc, err := NewPlainTextDocument(data, thread.NewInMemoryThread, "Some text") + if err != nil { + t.Fatalf("should not create document with error: %v", err) + } + assert.Equal(t, doc.Text(), "Some text") +} + +func TestDocument_PlainTextDocument_AddText(t *testing.T) { + keychain := threadbuilder.NewKeychain() + keychain.AddSigningKey("A") + keychain.AddEncryptionKey("A") + data := &account.AccountData{ + Identity: keychain.GetIdentity("A"), + SignKey: keychain.SigningKeys["A"], + EncKey: keychain.EncryptionKeys["A"], + } + + doc, err := NewPlainTextDocument(data, thread.NewInMemoryThread, "Some text") + if err != nil { + t.Fatalf("should not create document with error: %v", err) + } + + err = doc.AddText("Next") + if err != nil { + t.Fatalf("should be able to add document: %v", err) + } + assert.Equal(t, doc.Text(), "Some text|Next") +}