2022-07-12 08:45:13 +02:00

158 lines
3.6 KiB
Go

package plaintextdocument
import (
"fmt"
"github.com/anytypeio/go-anytype-infrastructure-experiments/account"
"github.com/anytypeio/go-anytype-infrastructure-experiments/acltree"
"github.com/anytypeio/go-anytype-infrastructure-experiments/testutils/testchanges/pb"
"github.com/anytypeio/go-anytype-infrastructure-experiments/thread"
"github.com/gogo/protobuf/proto"
)
type PlainTextDocument interface {
Text() string
AddText(text string) error
}
type plainTextDocument struct {
heads []string
aclTree acltree.ACLTree
state *DocumentState
}
func (p *plainTextDocument) Text() string {
return p.state.Text
}
func (p *plainTextDocument) AddText(text string) error {
_, err := p.aclTree.AddContent(func(builder acltree.ChangeBuilder) {
builder.AddChangeContent(
&pb.PlainTextChangeData{
Content: []*pb.PlainTextChangeContent{
createAppendTextChangeContent(text),
},
})
})
return err
}
func (p *plainTextDocument) Update(tree acltree.ACLTree) {
p.aclTree = tree
var err error
defer func() {
if err != nil {
fmt.Println("rebuild has returned error:", err)
}
}()
prevHeads := p.heads
p.heads = tree.Heads()
startId := prevHeads[0]
tree.IterateFrom(startId, func(change *acltree.Change) (isContinue bool) {
if change.Id == startId {
return true
}
if change.DecryptedDocumentChange != nil {
p.state, err = p.state.ApplyChange(change.DecryptedDocumentChange, change.Id)
if err != nil {
return false
}
}
return true
})
}
func (p *plainTextDocument) Rebuild(tree acltree.ACLTree) {
p.aclTree = tree
p.heads = tree.Heads()
var startId string
var err error
defer func() {
if err != nil {
fmt.Println("rebuild has returned error:", err)
}
}()
rootChange := tree.Root()
if rootChange.DecryptedDocumentChange == nil {
err = fmt.Errorf("root doesn't have decrypted change")
return
}
state, err := BuildDocumentStateFromChange(rootChange.DecryptedDocumentChange, rootChange.Id)
if err != nil {
return
}
startId = rootChange.Id
tree.Iterate(func(change *acltree.Change) (isContinue bool) {
if startId == change.Id {
return true
}
if change.DecryptedDocumentChange != nil {
state, err = state.ApplyChange(change.DecryptedDocumentChange, change.Id)
if err != nil {
return false
}
}
return true
})
if err != nil {
return
}
p.state = state
}
func NewInMemoryPlainTextDocument(acc *account.AccountData, text string) (PlainTextDocument, error) {
return NewPlainTextDocument(acc, thread.NewInMemoryThread, text)
}
func NewPlainTextDocument(
acc *account.AccountData,
create func(change *thread.RawChange) (thread.Thread, error),
text string) (PlainTextDocument, error) {
changeBuilder := func(builder acltree.ChangeBuilder) {
builder.UserAdd(acc.Identity, acc.EncKey.GetPublic())
builder.AddChangeContent(createInitialChangeContent(text))
}
t, err := acltree.BuildThreadWithACL(
acc,
changeBuilder,
create)
if err != nil {
return nil, err
}
doc := &plainTextDocument{
heads: nil,
aclTree: nil,
state: nil,
}
tree, err := acltree.BuildACLTree(t, acc, doc)
if err != nil {
return nil, err
}
doc.aclTree = tree
return doc, nil
}
func createInitialChangeContent(text string) proto.Marshaler {
return &pb.PlainTextChangeData{
Content: []*pb.PlainTextChangeContent{
createAppendTextChangeContent(text),
},
Snapshot: &pb.PlainTextChangeSnapshot{Text: text},
}
}
func createAppendTextChangeContent(text string) *pb.PlainTextChangeContent {
return &pb.PlainTextChangeContent{
Value: &pb.PlainTextChangeContentValueOfTextAppend{
TextAppend: &pb.PlainTextChangeTextAppend{
Text: text,
},
},
}
}