1
0
Fork 0
mirror of https://github.com/anyproto/any-sync.git synced 2025-06-08 05:57:03 +09:00
any-sync/commonspace/object/tree/objecttree/objecttreefactory.go
2025-01-23 15:25:51 +01:00

314 lines
9.4 KiB
Go

package objecttree
import (
"context"
"fmt"
"github.com/anyproto/any-sync/commonspace/object/acl/list"
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
"github.com/anyproto/any-sync/util/crypto"
)
type ObjectTreeCreatePayload struct {
PrivKey crypto.PrivKey
ChangeType string
ChangePayload []byte
SpaceId string
IsEncrypted bool
Seed []byte
Timestamp int64
}
type ObjectTreeDerivePayload struct {
ChangeType string
ChangePayload []byte
SpaceId string
IsEncrypted bool
}
type HistoryTreeParams struct {
Storage Storage
AclList list.AclList
Heads []string
IncludeBeforeId bool
}
type objectTreeDeps struct {
changeBuilder ChangeBuilder
treeBuilder *treeBuilder
storage Storage
validator ObjectTreeValidator
aclList list.AclList
flusher Flusher
}
type BuildObjectTreeFunc = func(storage Storage, aclList list.AclList) (ObjectTree, error)
var defaultObjectTreeDeps = verifiableTreeDeps
func verifiableTreeDeps(
rootChange *treechangeproto.RawTreeChangeWithId,
storage Storage,
aclList list.AclList) objectTreeDeps {
changeBuilder := NewChangeBuilder(crypto.NewKeyStorage(), rootChange)
treeBuilder := newTreeBuilder(storage, changeBuilder)
return objectTreeDeps{
changeBuilder: changeBuilder,
treeBuilder: treeBuilder,
storage: storage,
validator: newTreeValidator(false, false),
aclList: aclList,
flusher: &defaultFlusher{},
}
}
var emptyDataTreeDeps = verifiableEmptyDataTreeDeps
func verifiableEmptyDataTreeDeps(
rootChange *treechangeproto.RawTreeChangeWithId,
storage Storage,
aclList list.AclList) objectTreeDeps {
changeBuilder := NewEmptyDataChangeBuilder(crypto.NewKeyStorage(), rootChange)
treeBuilder := newTreeBuilder(storage, changeBuilder)
return objectTreeDeps{
changeBuilder: changeBuilder,
treeBuilder: treeBuilder,
storage: storage,
validator: newTreeValidator(false, false),
aclList: aclList,
flusher: &defaultFlusher{},
}
}
func nonVerifiableEmptyDataTreeDeps(
rootChange *treechangeproto.RawTreeChangeWithId,
storage Storage,
aclList list.AclList) objectTreeDeps {
changeBuilder := &nonVerifiableChangeBuilder{NewEmptyDataChangeBuilder(crypto.NewKeyStorage(), rootChange)}
treeBuilder := newTreeBuilder(storage, changeBuilder)
return objectTreeDeps{
changeBuilder: changeBuilder,
treeBuilder: treeBuilder,
storage: storage,
validator: newTreeValidator(false, false),
aclList: aclList,
flusher: &defaultFlusher{},
}
}
func nonVerifiableTreeDeps(
rootChange *treechangeproto.RawTreeChangeWithId,
storage Storage,
aclList list.AclList) objectTreeDeps {
changeBuilder := &nonVerifiableChangeBuilder{NewChangeBuilder(newMockKeyStorage(), rootChange)}
treeBuilder := newTreeBuilder(storage, changeBuilder)
return objectTreeDeps{
changeBuilder: changeBuilder,
treeBuilder: treeBuilder,
storage: storage,
validator: &noOpTreeValidator{},
aclList: aclList,
flusher: &defaultFlusher{},
}
}
func BuildEmptyDataObjectTree(storage Storage, aclList list.AclList) (ObjectTree, error) {
rootChange, err := storage.Root(context.Background())
if err != nil {
return nil, err
}
deps := emptyDataTreeDeps(rootChange.RawTreeChangeWithId(), storage, aclList)
return buildObjectTree(deps)
}
func BuildTestableTree(storage Storage, aclList list.AclList) (ObjectTree, error) {
root, _ := storage.Root(context.Background())
changeBuilder := &nonVerifiableChangeBuilder{
ChangeBuilder: NewChangeBuilder(newMockKeyStorage(), root.RawTreeChangeWithId()),
}
deps := objectTreeDeps{
changeBuilder: changeBuilder,
treeBuilder: newTreeBuilder(storage, changeBuilder),
storage: storage,
validator: &noOpTreeValidator{},
aclList: aclList,
flusher: &defaultFlusher{},
}
return buildObjectTree(deps)
}
func BuildEmptyDataTestableTree(storage Storage, aclList list.AclList) (ObjectTree, error) {
root, _ := storage.Root(context.Background())
changeBuilder := &nonVerifiableChangeBuilder{
ChangeBuilder: NewEmptyDataChangeBuilder(newMockKeyStorage(), root.RawTreeChangeWithId()),
}
deps := objectTreeDeps{
changeBuilder: changeBuilder,
treeBuilder: newTreeBuilder(storage, changeBuilder),
storage: storage,
validator: &noOpTreeValidator{},
aclList: aclList,
flusher: &defaultFlusher{},
}
return buildObjectTree(deps)
}
func BuildMigratableObjectTree(storage Storage, aclList list.AclList) (ObjectTree, error) {
rootChange, err := storage.Root(context.Background())
if err != nil {
return nil, fmt.Errorf("failed to get root: %w", err)
}
deps := nonVerifiableEmptyDataTreeDeps(rootChange.RawTreeChangeWithId(), storage, aclList)
return buildObjectTree(deps)
}
func BuildKeyFilterableObjectTree(storage Storage, aclList list.AclList) (ObjectTree, error) {
rootChange, err := storage.Root(context.Background())
if err != nil {
return nil, err
}
deps := defaultObjectTreeDeps(rootChange.RawTreeChangeWithId(), storage, aclList)
deps.validator = newTreeValidator(true, true)
return buildObjectTree(deps)
}
func BuildEmptyDataKeyFilterableObjectTree(storage Storage, aclList list.AclList) (ObjectTree, error) {
rootChange, err := storage.Root(context.Background())
if err != nil {
return nil, err
}
deps := emptyDataTreeDeps(rootChange.RawTreeChangeWithId(), storage, aclList)
deps.validator = newTreeValidator(true, true)
return buildObjectTree(deps)
}
func BuildObjectTree(storage Storage, aclList list.AclList) (ObjectTree, error) {
rootChange, err := storage.Root(context.Background())
if err != nil {
return nil, err
}
deps := defaultObjectTreeDeps(rootChange.RawTreeChangeWithId(), storage, aclList)
return buildObjectTree(deps)
}
func BuildNonVerifiableHistoryTree(params HistoryTreeParams) (HistoryTree, error) {
rootChange, err := params.Storage.Root(context.Background())
if err != nil {
return nil, err
}
deps := nonVerifiableTreeDeps(rootChange.RawTreeChangeWithId(), params.Storage, params.AclList)
return buildHistoryTree(deps, params)
}
func BuildHistoryTree(params HistoryTreeParams) (HistoryTree, error) {
rootChange, err := params.Storage.Root(context.Background())
if err != nil {
return nil, err
}
deps := defaultObjectTreeDeps(rootChange.RawTreeChangeWithId(), params.Storage, params.AclList)
return buildHistoryTree(deps, params)
}
func CreateObjectTreeRoot(payload ObjectTreeCreatePayload, aclList list.AclList) (root *treechangeproto.RawTreeChangeWithId, err error) {
aclList.RLock()
aclHeadId := aclList.Head().Id
aclList.RUnlock()
cnt := InitialContent{
AclHeadId: aclHeadId,
PrivKey: payload.PrivKey,
SpaceId: payload.SpaceId,
ChangeType: payload.ChangeType,
ChangePayload: payload.ChangePayload,
Timestamp: payload.Timestamp,
Seed: payload.Seed,
}
_, root, err = NewChangeBuilder(crypto.NewKeyStorage(), nil).BuildRoot(cnt)
return
}
func DeriveObjectTreeRoot(payload ObjectTreeDerivePayload, aclList list.AclList) (root *treechangeproto.RawTreeChangeWithId, err error) {
cnt := InitialDerivedContent{
SpaceId: payload.SpaceId,
ChangeType: payload.ChangeType,
ChangePayload: payload.ChangePayload,
}
_, root, err = NewChangeBuilder(crypto.NewKeyStorage(), nil).BuildDerivedRoot(cnt)
return
}
func buildObjectTree(deps objectTreeDeps) (ObjectTree, error) {
objTree := &objectTree{
id: deps.storage.Id(),
storage: deps.storage,
treeBuilder: deps.treeBuilder,
validator: deps.validator,
aclList: deps.aclList,
changeBuilder: deps.changeBuilder,
keys: make(map[string]crypto.SymKey),
newChangesBuf: make([]*Change, 0, 10),
difSnapshotBuf: make([]*treechangeproto.RawTreeChangeWithId, 0, 10),
notSeenIdxBuf: make([]int, 0, 10),
newSnapshotsBuf: make([]*Change, 0, 10),
flusher: deps.flusher,
}
err := objTree.rebuildFromStorage(nil, nil, nil)
if err != nil {
return nil, fmt.Errorf("failed to rebuild from storage: %w", err)
}
// TODO: think about contexts
root, err := objTree.storage.Root(context.Background())
if err != nil {
return nil, err
}
objTree.rawRoot = root.RawTreeChangeWithId()
// verifying root
header, err := objTree.changeBuilder.Unmarshall(objTree.rawRoot, true)
if err != nil {
return nil, err
}
objTree.root = header
return objTree, nil
}
func buildHistoryTree(deps objectTreeDeps, params HistoryTreeParams) (ht HistoryTree, err error) {
objTree := &objectTree{
id: deps.storage.Id(),
storage: deps.storage,
treeBuilder: deps.treeBuilder,
validator: deps.validator,
aclList: deps.aclList,
changeBuilder: deps.changeBuilder,
keys: make(map[string]crypto.SymKey),
newChangesBuf: make([]*Change, 0, 10),
difSnapshotBuf: make([]*treechangeproto.RawTreeChangeWithId, 0, 10),
notSeenIdxBuf: make([]int, 0, 10),
newSnapshotsBuf: make([]*Change, 0, 10),
flusher: deps.flusher,
}
hTree := &historyTree{objectTree: objTree}
err = hTree.rebuildFromStorage(params)
if err != nil {
return nil, err
}
objTree.id = objTree.storage.Id()
root, err := objTree.storage.Root(context.Background())
if err != nil {
return nil, err
}
objTree.rawRoot = root.RawTreeChangeWithId()
header, err := objTree.changeBuilder.Unmarshall(objTree.rawRoot, false)
if err != nil {
return nil, err
}
objTree.root = header
return hTree, nil
}