Add updated changes to thread builder

This commit is contained in:
mcrakhman 2022-07-07 08:47:11 +02:00 committed by Mikhail Iudin
parent f15c806415
commit 475904a266
No known key found for this signature in database
GPG Key ID: FAAAA8BAABDFF1C0
3 changed files with 125 additions and 78 deletions

View File

@ -24,17 +24,19 @@ type threadChange struct {
} }
type ThreadBuilder struct { type ThreadBuilder struct {
threadId string threadId string
allChanges map[string]*threadChange allChanges map[string]*threadChange
heads []string updatedChanges map[string]*threadChange
maybeHeads []string heads []string
keychain *Keychain maybeHeads []string
keychain *Keychain
} }
func NewThreadBuilder(keychain *Keychain) *ThreadBuilder { func NewThreadBuilder(keychain *Keychain) *ThreadBuilder {
return &ThreadBuilder{ return &ThreadBuilder{
allChanges: make(map[string]*threadChange), allChanges: make(map[string]*threadChange),
keychain: keychain, updatedChanges: make(map[string]*threadChange),
keychain: keychain,
} }
} }
@ -121,7 +123,20 @@ func (t *ThreadBuilder) SetHeads(heads []string) {
} }
func (t *ThreadBuilder) GetChange(ctx context.Context, recordID string) (*threadmodels.RawChange, error) { func (t *ThreadBuilder) GetChange(ctx context.Context, recordID string) (*threadmodels.RawChange, error) {
rec := t.allChanges[recordID] return t.getChange(recordID, t.allChanges), nil
}
func (t *ThreadBuilder) GetUpdatedChanges() []*threadmodels.RawChange {
var res []*threadmodels.RawChange
for _, ch := range t.updatedChanges {
rawCh := t.getChange(ch.id, t.updatedChanges)
res = append(res, rawCh)
}
return res
}
func (t *ThreadBuilder) getChange(changeId string, m map[string]*threadChange) *threadmodels.RawChange {
rec := m[changeId]
if rec.changesDataDecrypted != nil { if rec.changesDataDecrypted != nil {
encrypted, err := rec.readKey.Key.Encrypt(rec.changesDataDecrypted) encrypted, err := rec.readKey.Key.Encrypt(rec.changesDataDecrypted)
@ -145,13 +160,9 @@ func (t *ThreadBuilder) GetChange(ctx context.Context, recordID string) (*thread
transformedRec := &threadmodels.RawChange{ transformedRec := &threadmodels.RawChange{
Payload: aclMarshaled, Payload: aclMarshaled,
Signature: signature, Signature: signature,
Id: recordID, Id: changeId,
} }
return transformedRec, nil return transformedRec
}
func (t *ThreadBuilder) PushChange(payload proto.Marshaler) (id string, err error) {
panic("implement me")
} }
func (t *ThreadBuilder) Parse(thread *YMLThread) { func (t *ThreadBuilder) Parse(thread *YMLThread) {
@ -161,55 +172,66 @@ func (t *ThreadBuilder) Parse(thread *YMLThread) {
t.keychain.ParseKeys(&thread.Keys) t.keychain.ParseKeys(&thread.Keys)
t.threadId = t.parseThreadId(thread.Description) t.threadId = t.parseThreadId(thread.Description)
for _, ch := range thread.Changes { for _, ch := range thread.Changes {
newChange := &threadChange{ newChange := t.parseChange(ch)
id: ch.Id,
}
k := t.keychain.GetKey(ch.ReadKey).(*SymKey)
newChange.readKey = k
newChange.signKey = t.keychain.SigningKeys[ch.Identity]
aclChange := &pb.ACLChange{}
aclChange.Identity = t.keychain.GetIdentity(ch.Identity)
if len(ch.AclChanges) > 0 || ch.AclSnapshot != nil {
aclChange.AclData = &pb.ACLChangeACLData{}
if ch.AclSnapshot != nil {
aclChange.AclData.AclSnapshot = t.parseACLSnapshot(ch.AclSnapshot)
}
if ch.AclChanges != nil {
var aclChangeContents []*pb.ACLChangeACLContentValue
for _, ch := range ch.AclChanges {
aclChangeContent := t.parseACLChange(ch)
aclChangeContents = append(aclChangeContents, aclChangeContent)
}
aclChange.AclData.AclContent = aclChangeContents
}
}
if len(ch.Changes) > 0 || ch.Snapshot != nil {
changesData := &pb.PlainTextChangeData{}
if ch.Snapshot != nil {
changesData.Snapshot = t.parseChangeSnapshot(ch.Snapshot)
}
if len(ch.Changes) > 0 {
var changeContents []*pb.PlainTextChangeContent
for _, ch := range ch.Changes {
aclChangeContent := t.parseDocumentChange(ch)
changeContents = append(changeContents, aclChangeContent)
}
changesData.Content = changeContents
}
m, err := proto.Marshal(changesData)
if err != nil {
return
}
newChange.changesDataDecrypted = m
}
aclChange.CurrentReadKeyHash = k.Hash
newChange.ACLChange = aclChange
t.allChanges[newChange.id] = newChange t.allChanges[newChange.id] = newChange
} }
for _, ch := range thread.UpdatedChanges {
newChange := t.parseChange(ch)
t.updatedChanges[newChange.id] = newChange
}
t.parseGraph(thread) t.parseGraph(thread)
t.parseHeads(thread) t.parseHeads(thread)
} }
func (t *ThreadBuilder) parseChange(ch *Change) *threadChange {
newChange := &threadChange{
id: ch.Id,
}
k := t.keychain.GetKey(ch.ReadKey).(*SymKey)
newChange.readKey = k
newChange.signKey = t.keychain.SigningKeys[ch.Identity]
aclChange := &pb.ACLChange{}
aclChange.Identity = t.keychain.GetIdentity(ch.Identity)
if len(ch.AclChanges) > 0 || ch.AclSnapshot != nil {
aclChange.AclData = &pb.ACLChangeACLData{}
if ch.AclSnapshot != nil {
aclChange.AclData.AclSnapshot = t.parseACLSnapshot(ch.AclSnapshot)
}
if ch.AclChanges != nil {
var aclChangeContents []*pb.ACLChangeACLContentValue
for _, ch := range ch.AclChanges {
aclChangeContent := t.parseACLChange(ch)
aclChangeContents = append(aclChangeContents, aclChangeContent)
}
aclChange.AclData.AclContent = aclChangeContents
}
}
if len(ch.Changes) > 0 || ch.Snapshot != nil {
changesData := &pb.PlainTextChangeData{}
if ch.Snapshot != nil {
changesData.Snapshot = t.parseChangeSnapshot(ch.Snapshot)
}
if len(ch.Changes) > 0 {
var changeContents []*pb.PlainTextChangeContent
for _, ch := range ch.Changes {
aclChangeContent := t.parseDocumentChange(ch)
changeContents = append(changeContents, aclChangeContent)
}
changesData.Content = changeContents
}
m, err := proto.Marshal(changesData)
if err != nil {
return nil
}
newChange.changesDataDecrypted = m
}
aclChange.CurrentReadKeyHash = k.Hash
newChange.ACLChange = aclChange
return newChange
}
func (t *ThreadBuilder) parseThreadId(description *ThreadDescription) string { func (t *ThreadBuilder) parseThreadId(description *ThreadDescription) string {
if description == nil { if description == nil {
panic("no author in thread") panic("no author in thread")
@ -415,8 +437,8 @@ func (t *ThreadBuilder) convertPermission(perm string) pb.ACLChangeUserPermissio
func (t *ThreadBuilder) traverseFromHeads(f func(t *threadChange) error) error { func (t *ThreadBuilder) traverseFromHeads(f func(t *threadChange) error) error {
uniqMap := map[string]struct{}{} uniqMap := map[string]struct{}{}
stack := make([]string, len(t.heads), 10) stack := make([]string, len(t.maybeHeads), 10)
copy(stack, t.heads) copy(stack, t.maybeHeads)
for len(stack) > 0 { for len(stack) > 0 {
id := stack[len(stack)-1] id := stack[len(stack)-1]
stack = stack[:len(stack)-1] stack = stack[:len(stack)-1]
@ -444,6 +466,13 @@ func (t *ThreadBuilder) parseGraph(thread *YMLThread) {
rec.TreeHeadIds = node.TreeHeads rec.TreeHeadIds = node.TreeHeads
rec.SnapshotBaseId = node.BaseSnapshot rec.SnapshotBaseId = node.BaseSnapshot
} }
for _, node := range thread.UpdatedGraph {
rec := t.updatedChanges[node.Id]
rec.AclHeadIds = node.ACLHeads
rec.TreeHeadIds = node.TreeHeads
rec.SnapshotBaseId = node.BaseSnapshot
}
} }
func (t *ThreadBuilder) parseHeads(thread *YMLThread) { func (t *ThreadBuilder) parseHeads(thread *YMLThread) {

View File

@ -101,3 +101,15 @@ graph:
treeHeads: [B.1.1] treeHeads: [B.1.1]
maybeHeads: maybeHeads:
- "A.1.3" - "A.1.3"
updatedChanges:
- id: B.1.3
identity: B
changes:
- textAppend:
text: "first"
readKey: key.Read.1
updatedGraph:
- id: B.1.3
baseSnapshot: A.1.1
aclHeads: [ B.1.1 ]
treeHeads: [ B.1.2 ]

View File

@ -70,29 +70,35 @@ type PlainTextChange struct {
} `yaml:"textAppend"` } `yaml:"textAppend"`
} }
type GraphNode struct {
Id string `yaml:"id"`
BaseSnapshot string `yaml:"baseSnapshot"`
AclSnapshot string `yaml:"aclSnapshot"`
ACLHeads []string `yaml:"aclHeads"`
TreeHeads []string `yaml:"treeHeads"`
}
type Change struct {
Id string `yaml:"id"`
Identity string `yaml:"identity"`
AclSnapshot *ACLSnapshot `yaml:"aclSnapshot"`
Snapshot *PlainTextSnapshot `yaml:"snapshot"`
AclChanges []*ACLChange `yaml:"aclChanges"`
Changes []*PlainTextChange `yaml:"changes"`
ReadKey string `yaml:"readKey"`
}
type YMLThread struct { type YMLThread struct {
Description *ThreadDescription `yaml:"thread"` Description *ThreadDescription `yaml:"thread"`
Changes []struct { Changes []*Change `yaml:"changes"`
Id string `yaml:"id"` UpdatedChanges []*Change `yaml:"updatedChanges"`
Identity string `yaml:"identity"`
AclSnapshot *ACLSnapshot `yaml:"aclSnapshot"`
Snapshot *PlainTextSnapshot `yaml:"snapshot"`
AclChanges []*ACLChange `yaml:"aclChanges"`
Changes []*PlainTextChange `yaml:"changes"`
ReadKey string `yaml:"readKey"`
} `yaml:"changes"`
Keys Keys `yaml:"keys"` Keys Keys `yaml:"keys"`
Graph []struct { Graph []*GraphNode `yaml:"graph"`
Id string `yaml:"id"` UpdatedGraph []*GraphNode `yaml:"updatedGraph"`
BaseSnapshot string `yaml:"baseSnapshot"`
AclSnapshot string `yaml:"aclSnapshot"`
ACLHeads []string `yaml:"aclHeads"`
TreeHeads []string `yaml:"treeHeads"`
} `yaml:"graph"`
Heads []string `yaml:"heads"` Heads []string `yaml:"heads"`
MaybeHeads []string `yaml:"maybeHeads"` MaybeHeads []string `yaml:"maybeHeads"`