diff --git a/pkg/acl/tree/acltree.go b/pkg/acl/tree/acltree.go index 5e393022..2b5563b2 100644 --- a/pkg/acl/tree/acltree.go +++ b/pkg/acl/tree/acltree.go @@ -30,7 +30,7 @@ type AddResult struct { Summary AddResultSummary } -type TreeUpdateListener interface { +type ACLTreeUpdateListener interface { Update(tree ACLTree) Rebuild(tree ACLTree) } @@ -72,7 +72,7 @@ type ACLTree interface { type aclTree struct { treeStorage treestorage.TreeStorage accountData *account.AccountData - updateListener TreeUpdateListener + updateListener ACLTreeUpdateListener id string header *treepb.TreeHeader @@ -86,7 +86,7 @@ type aclTree struct { sync.RWMutex } -func BuildACLTreeWithIdentity(t treestorage.TreeStorage, acc *account.AccountData, listener TreeUpdateListener) (ACLTree, error) { +func BuildACLTreeWithIdentity(t treestorage.TreeStorage, acc *account.AccountData, listener ACLTreeUpdateListener) (ACLTree, error) { treeBuilder := newTreeBuilder(t, acc.Decoder) aclStateBuilder := newACLStateBuilderWithIdentity(acc.Decoder, acc) changeBuilder := newACLChangeBuilder() @@ -127,7 +127,7 @@ func BuildACLTreeWithIdentity(t treestorage.TreeStorage, acc *account.AccountDat return aclTree, nil } -func BuildACLTree(t treestorage.TreeStorage, decoder signingkey.PubKeyDecoder, listener TreeUpdateListener) (ACLTree, error) { +func BuildACLTree(t treestorage.TreeStorage, decoder signingkey.PubKeyDecoder, listener ACLTreeUpdateListener) (ACLTree, error) { treeBuilder := newTreeBuilder(t, decoder) aclStateBuilder := newACLStateBuilder() changeBuilder := newACLChangeBuilder() diff --git a/pkg/acl/tree/changevalidator.go b/pkg/acl/tree/changevalidator.go index a11d52c0..fc2ec75c 100644 --- a/pkg/acl/tree/changevalidator.go +++ b/pkg/acl/tree/changevalidator.go @@ -1,18 +1,15 @@ package tree -type ChangeValidator interface { - ValidateChange(change *Change) error +type DocTreeValidator interface { + ValidateTree(tree *Tree, aclTree ACLTree) error } -type defChangeValidator struct { - aclTree ACLTree -} +type docTreeValidator struct{} -func NewDefChangeValidator(aclTree ACLTree) ChangeValidator { - return &defChangeValidator{} +func newTreeValidator() DocTreeValidator { + return &docTreeValidator{} } - -func (c *defChangeValidator) ValidateChange(change *Change) error { +func (v *docTreeValidator) ValidateTree(tree *Tree, aclTree ACLTree) error { // TODO: add validation logic where we check that the change refers to correct acl heads // that means that more recent changes should refer to more recent acl heads return nil diff --git a/pkg/acl/tree/descriptionparser.go b/pkg/acl/tree/descriptionparser.go index c483eedc..367afdec 100644 --- a/pkg/acl/tree/descriptionparser.go +++ b/pkg/acl/tree/descriptionparser.go @@ -12,6 +12,14 @@ type DescriptionParser interface { ParseChange(*Change) ([]string, error) } +var NoOpDescriptionParser = noopDescriptionParser{} + +type noopDescriptionParser struct{} + +func (n noopDescriptionParser) ParseChange(change *Change) ([]string, error) { + return []string{"DOC"}, nil +} + var ACLDescriptionParser = aclDescriptionParser{} type aclDescriptionParser struct{} diff --git a/pkg/acl/tree/doctree.go b/pkg/acl/tree/doctree.go index 20470b01..a9068b71 100644 --- a/pkg/acl/tree/doctree.go +++ b/pkg/acl/tree/doctree.go @@ -6,17 +6,25 @@ import ( "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclchanges/aclpb" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treestorage" "github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treestorage/treepb" + "github.com/anytypeio/go-anytype-infrastructure-experiments/util/cid" + "github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/signingkey" "github.com/gogo/protobuf/proto" "go.uber.org/zap" "sync" + "time" ) +type TreeUpdateListener interface { + Update(tree DocTree) + Rebuild(tree DocTree) +} + type DocTree interface { RWLocker ID() string Header() *treepb.TreeHeader - AddContent(ctx context.Context, content proto.Marshaler) (*aclpb.RawChange, error) - AddRawChanges(ctx context.Context, validator ChangeValidator, changes ...*aclpb.RawChange) (AddResult, error) + AddContent(ctx context.Context, aclTree ACLTree, content proto.Marshaler, isSnapshot bool) (*aclpb.RawChange, error) + AddRawChanges(ctx context.Context, aclTree ACLTree, changes ...*aclpb.RawChange) (AddResult, error) Heads() []string Root() *Change Iterate(func(change *Change) bool) @@ -41,29 +49,25 @@ type docTree struct { aclState *ACLState treeBuilder *treeBuilder + validator DocTreeValidator sync.RWMutex } -func BuildDocTreeWithIdentity( - t treestorage.TreeStorage, - acc *account.AccountData, - listener TreeUpdateListener) (DocTree, error) { +func BuildDocTreeWithIdentity(t treestorage.TreeStorage, acc *account.AccountData, listener TreeUpdateListener, aclTree ACLTree) (DocTree, error) { treeBuilder := newTreeBuilder(t, acc.Decoder) - aclStateBuilder := newACLStateBuilderWithIdentity(acc.Decoder, acc) - changeBuilder := newChangeBuilder() + validator := newTreeValidator() docTree := &docTree{ - treeStorage: t, - accountData: acc, - tree: nil, - aclState: nil, - treeBuilder: treeBuilder, - aclStateBuilder: aclStateBuilder, - changeBuilder: changeBuilder, - updateListener: listener, + treeStorage: t, + accountData: acc, + tree: nil, + aclState: nil, + treeBuilder: treeBuilder, + validator: validator, + updateListener: listener, } - err := docTree.rebuildFromStorage() + err := docTree.rebuildFromStorage(aclTree) if err != nil { return nil, err } @@ -89,106 +93,155 @@ func BuildDocTreeWithIdentity( return docTree, nil } -func BuildACLTree(t treestorage.TreeStorage) { - // TODO: Add logic for building without identity +func BuildDocTree(t treestorage.TreeStorage, decoder signingkey.PubKeyDecoder, listener TreeUpdateListener, aclTree ACLTree) (DocTree, error) { + treeBuilder := newTreeBuilder(t, decoder) + validator := newTreeValidator() + + docTree := &docTree{ + treeStorage: t, + tree: nil, + aclState: nil, + treeBuilder: treeBuilder, + validator: validator, + updateListener: listener, + } + err := docTree.rebuildFromStorage(aclTree) + if err != nil { + return nil, err + } + err = docTree.removeOrphans() + if err != nil { + return nil, err + } + err = t.SetHeads(docTree.Heads()) + if err != nil { + return nil, err + } + docTree.id, err = t.TreeID() + if err != nil { + return nil, err + } + docTree.header, err = t.Header() + if err != nil { + return nil, err + } + + listener.Rebuild(docTree) + + return docTree, nil } -func (a *docTree) removeOrphans() error { +func (d *docTree) removeOrphans() error { // removing attached or invalid orphans var toRemove []string - orphans, err := a.treeStorage.Orphans() + orphans, err := d.treeStorage.Orphans() if err != nil { return err } for _, orphan := range orphans { - if _, exists := a.tree.attached[orphan]; exists { + if _, exists := d.tree.attached[orphan]; exists { toRemove = append(toRemove, orphan) } - if _, exists := a.tree.invalidChanges[orphan]; exists { + if _, exists := d.tree.invalidChanges[orphan]; exists { toRemove = append(toRemove, orphan) } } - return a.treeStorage.RemoveOrphans(toRemove...) + return d.treeStorage.RemoveOrphans(toRemove...) } -func (a *docTree) rebuildFromStorage() (err error) { - a.treeBuilder.Init() +func (d *docTree) rebuildFromStorage(aclTree ACLTree) (err error) { + d.treeBuilder.Init() - a.tree, err = a.treeBuilder.Build(false) + d.tree, err = d.treeBuilder.Build(false) if err != nil { return err } - err = a.aclStateBuilder.Init(a.tree) - if err != nil { - return err - } - - a.aclState, err = a.aclStateBuilder.Build() - if err != nil { - return err - } - - return nil + return d.validator.ValidateTree(d.tree, aclTree) } -func (a *docTree) ID() string { - return a.id +func (d *docTree) ID() string { + return d.id } -func (a *docTree) Header() *treepb.TreeHeader { - return a.header +func (d *docTree) Header() *treepb.TreeHeader { + return d.header } -func (a *docTree) ACLState() *ACLState { - return a.aclState +func (d *docTree) Storage() treestorage.TreeStorage { + return d.treeStorage } -func (a *docTree) Storage() treestorage.TreeStorage { - return a.treeStorage -} - -func (a *docTree) AddContent(ctx context.Context, build func(builder ChangeBuilder) error) (*aclpb.RawChange, error) { - if a.accountData == nil { +func (d *docTree) AddContent(ctx context.Context, aclTree ACLTree, content proto.Marshaler, isSnapshot bool) (*aclpb.RawChange, error) { + if d.accountData == nil { return nil, ErrTreeWithoutIdentity } defer func() { // TODO: should this be called in a separate goroutine to prevent accidental cycles (tree->updater->tree) - a.updateListener.Update(a) + d.updateListener.Update(d) }() + state := aclTree.ACLState() + change := &aclpb.Change{ + TreeHeadIds: d.tree.Heads(), + AclHeadIds: aclTree.Heads(), + SnapshotBaseId: d.tree.RootId(), + CurrentReadKeyHash: state.currentReadKeyHash, + Timestamp: int64(time.Now().Nanosecond()), + Identity: d.accountData.Identity, + } - a.changeBuilder.Init(a.aclState, a.tree, a.accountData) - err := build(a.changeBuilder) + marshalledData, err := content.Marshal() if err != nil { return nil, err } - - ch, marshalled, err := a.changeBuilder.BuildAndApply() + encrypted, err := state.userReadKeys[state.currentReadKeyHash].Encrypt(marshalledData) if err != nil { return nil, err } - a.tree.AddFast(ch) + change.ChangesData = encrypted + + fullMarshalledChange, err := proto.Marshal(change) + if err != nil { + return nil, err + } + signature, err := d.accountData.SignKey.Sign(fullMarshalledChange) + if err != nil { + return nil, err + } + id, err := cid.NewCIDFromBytes(fullMarshalledChange) + if err != nil { + return nil, err + } + ch := NewChange(id, change) + ch.ParsedModel = content + ch.Sign = signature + + if isSnapshot { + // clearing tree, because we already fixed everything in the last snapshot + d.tree = &Tree{} + } + d.tree.AddFast(ch) rawCh := &aclpb.RawChange{ - Payload: marshalled, + Payload: fullMarshalledChange, Signature: ch.Signature(), Id: ch.Id, } - err = a.treeStorage.AddRawChange(rawCh) + err = d.treeStorage.AddRawChange(rawCh) if err != nil { return nil, err } - err = a.treeStorage.SetHeads([]string{ch.Id}) + err = d.treeStorage.SetHeads([]string{ch.Id}) if err != nil { return nil, err } return rawCh, nil } -func (a *docTree) AddRawChanges(ctx context.Context, rawChanges ...*aclpb.RawChange) (AddResult, error) { +func (d *docTree) AddRawChanges(ctx context.Context, aclTree ACLTree, rawChanges ...*aclpb.RawChange) (AddResult, error) { // TODO: make proper error handling, because there are a lot of corner cases where this will break var err error var mode Mode @@ -208,21 +261,21 @@ func (a *docTree) AddRawChanges(ctx context.Context, rawChanges ...*aclpb.RawCha return } - err = a.removeOrphans() + err = d.removeOrphans() if err != nil { return } - err = a.treeStorage.SetHeads(a.tree.Heads()) + err = d.treeStorage.SetHeads(d.tree.Heads()) if err != nil { return } switch mode { case Append: - a.updateListener.Update(a) + d.updateListener.Update(d) case Rebuild: - a.updateListener.Rebuild(a) + d.updateListener.Rebuild(d) default: break } @@ -231,28 +284,49 @@ func (a *docTree) AddRawChanges(ctx context.Context, rawChanges ...*aclpb.RawCha getAddedChanges := func() []*aclpb.RawChange { var added []*aclpb.RawChange for _, ch := range rawChanges { - if _, exists := a.tree.attached[ch.Id]; exists { + if _, exists := d.tree.attached[ch.Id]; exists { added = append(added, ch) } } return added } - for _, ch := range changes { - err = a.treeStorage.AddChange(ch) + prevHeads := d.tree.Heads() + rebuild := func() (AddResult, error) { + err = d.rebuildFromStorage(aclTree) if err != nil { return AddResult{}, err } - err = a.treeStorage.AddOrphans(ch.Id) + + return AddResult{ + OldHeads: prevHeads, + Heads: d.tree.Heads(), + Added: getAddedChanges(), + Summary: AddResultSummaryRebuild, + }, nil + } + + for _, ch := range changes { + err = d.treeStorage.AddChange(ch) + if err != nil { + return AddResult{}, err + } + err = d.treeStorage.AddOrphans(ch.Id) if err != nil { return AddResult{}, err } } - prevHeads := a.tree.Heads() - mode = a.tree.Add(changes...) + mode = d.tree.Add(changes...) switch mode { case Nothing: + for _, ch := range changes { + // rebuilding if the snapshot is different from the root + if ch.SnapshotId != d.tree.RootId() { + return rebuild() + } + } + return AddResult{ OldHeads: prevHeads, Heads: prevHeads, @@ -260,69 +334,59 @@ func (a *docTree) AddRawChanges(ctx context.Context, rawChanges ...*aclpb.RawCha }, nil case Rebuild: - err = a.rebuildFromStorage() - if err != nil { - return AddResult{}, err - } - - return AddResult{ - OldHeads: prevHeads, - Heads: a.tree.Heads(), - Added: getAddedChanges(), - Summary: AddResultSummaryRebuild, - }, nil + return rebuild() default: // just rebuilding the state from start without reloading everything from tree storage // as an optimization we could've started from current heads, but I didn't implement that - a.aclState, err = a.aclStateBuilder.Build() + err = d.validator.ValidateTree(d.tree, aclTree) if err != nil { return AddResult{}, err } return AddResult{ OldHeads: prevHeads, - Heads: a.tree.Heads(), + Heads: d.tree.Heads(), Added: getAddedChanges(), Summary: AddResultSummaryAppend, }, nil } } -func (a *docTree) Iterate(f func(change *Change) bool) { - a.tree.Iterate(a.tree.RootId(), f) +func (d *docTree) Iterate(f func(change *Change) bool) { + d.tree.Iterate(d.tree.RootId(), f) } -func (a *docTree) IterateFrom(s string, f func(change *Change) bool) { - a.tree.Iterate(s, f) +func (d *docTree) IterateFrom(s string, f func(change *Change) bool) { + d.tree.Iterate(s, f) } -func (a *docTree) HasChange(s string) bool { - _, attachedExists := a.tree.attached[s] - _, unattachedExists := a.tree.unAttached[s] - _, invalidExists := a.tree.invalidChanges[s] +func (d *docTree) HasChange(s string) bool { + _, attachedExists := d.tree.attached[s] + _, unattachedExists := d.tree.unAttached[s] + _, invalidExists := d.tree.invalidChanges[s] return attachedExists || unattachedExists || invalidExists } -func (a *docTree) Heads() []string { - return a.tree.Heads() +func (d *docTree) Heads() []string { + return d.tree.Heads() } -func (a *docTree) Root() *Change { - return a.tree.Root() +func (d *docTree) Root() *Change { + return d.tree.Root() } -func (a *docTree) Close() error { +func (d *docTree) Close() error { return nil } -func (a *docTree) SnapshotPath() []string { +func (d *docTree) SnapshotPath() []string { // TODO: think about caching this var path []string // TODO: think that the user may have not all of the snapshots locally - currentSnapshotId := a.tree.RootId() + currentSnapshotId := d.tree.RootId() for currentSnapshotId != "" { - sn, err := a.treeBuilder.loadChange(currentSnapshotId) + sn, err := d.treeBuilder.loadChange(currentSnapshotId) if err != nil { break } @@ -332,13 +396,13 @@ func (a *docTree) SnapshotPath() []string { return path } -func (a *docTree) ChangesAfterCommonSnapshot(theirPath []string) ([]*aclpb.RawChange, error) { +func (d *docTree) ChangesAfterCommonSnapshot(theirPath []string) ([]*aclpb.RawChange, error) { // TODO: think about when the clients will have their full acl tree and thus full snapshots // but no changes after some of the snapshots var ( isNewDocument = len(theirPath) == 0 - ourPath = a.SnapshotPath() + ourPath = d.SnapshotPath() // by default returning everything we have commonSnapshot = ourPath[len(ourPath)-1] // TODO: root snapshot, probably it is better to have a specific method in treestorage err error @@ -354,12 +418,12 @@ func (a *docTree) ChangesAfterCommonSnapshot(theirPath []string) ([]*aclpb.RawCh var rawChanges []*aclpb.RawChange // using custom load function to skip verification step and save raw changes load := func(id string) (*Change, error) { - raw, err := a.treeStorage.GetChange(context.Background(), id) + raw, err := d.treeStorage.GetChange(context.Background(), id) if err != nil { return nil, err } - aclChange, err := a.treeBuilder.makeUnverifiedACLChange(raw) + aclChange, err := d.treeBuilder.makeUnverifiedACLChange(raw) if err != nil { return nil, err } @@ -370,11 +434,11 @@ func (a *docTree) ChangesAfterCommonSnapshot(theirPath []string) ([]*aclpb.RawCh } // we presume that we have everything after the common snapshot, though this may not be the case in case of clients and only ACL tree changes log.With( - zap.Strings("heads", a.tree.Heads()), + zap.Strings("heads", d.tree.Heads()), zap.String("breakpoint", commonSnapshot), - zap.String("id", a.id)). + zap.String("id", d.id)). Debug("getting all changes from common snapshot") - _, err = a.treeBuilder.dfs(a.tree.Heads(), commonSnapshot, load) + _, err = d.treeBuilder.dfs(d.tree.Heads(), commonSnapshot, load) if err != nil { return nil, err } @@ -387,12 +451,12 @@ func (a *docTree) ChangesAfterCommonSnapshot(theirPath []string) ([]*aclpb.RawCh } log.With( zap.Int("len(changes)", len(rawChanges)), - zap.String("id", a.id)). + zap.String("id", d.id)). Debug("returning all changes after common snapshot") return rawChanges, nil } -func (a *docTree) DebugDump() (string, error) { - return a.tree.Graph(ACLDescriptionParser) +func (d *docTree) DebugDump() (string, error) { + return d.tree.Graph(NoOpDescriptionParser) } diff --git a/pkg/acl/treestorage/treepb/protos/tree.proto b/pkg/acl/treestorage/treepb/protos/tree.proto index eb342673..daf33e89 100644 --- a/pkg/acl/treestorage/treepb/protos/tree.proto +++ b/pkg/acl/treestorage/treepb/protos/tree.proto @@ -5,5 +5,11 @@ option go_package = "treepb"; message TreeHeader { string firstChangeId = 1; bool isWorkspace = 2; + TreeType type = 3; // TODO: add user identity, signature and nano timestamp + + enum TreeType { + ACLTree = 0; + DocTree = 1; + } } \ No newline at end of file diff --git a/pkg/acl/treestorage/treepb/tree.pb.go b/pkg/acl/treestorage/treepb/tree.pb.go index 7baa874c..bf05bfd8 100644 --- a/pkg/acl/treestorage/treepb/tree.pb.go +++ b/pkg/acl/treestorage/treepb/tree.pb.go @@ -22,9 +22,35 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +type TreeHeaderTreeType int32 + +const ( + TreeHeader_ACLTree TreeHeaderTreeType = 0 + TreeHeader_DocTree TreeHeaderTreeType = 1 +) + +var TreeHeaderTreeType_name = map[int32]string{ + 0: "ACLTree", + 1: "DocTree", +} + +var TreeHeaderTreeType_value = map[string]int32{ + "ACLTree": 0, + "DocTree": 1, +} + +func (x TreeHeaderTreeType) String() string { + return proto.EnumName(TreeHeaderTreeType_name, int32(x)) +} + +func (TreeHeaderTreeType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_e7d760b855878644, []int{0, 0} +} + type TreeHeader struct { - FirstChangeId string `protobuf:"bytes,1,opt,name=firstChangeId,proto3" json:"firstChangeId,omitempty"` - IsWorkspace bool `protobuf:"varint,2,opt,name=isWorkspace,proto3" json:"isWorkspace,omitempty"` + FirstChangeId string `protobuf:"bytes,1,opt,name=firstChangeId,proto3" json:"firstChangeId,omitempty"` + IsWorkspace bool `protobuf:"varint,2,opt,name=isWorkspace,proto3" json:"isWorkspace,omitempty"` + Type TreeHeaderTreeType `protobuf:"varint,3,opt,name=type,proto3,enum=tree.TreeHeaderTreeType" json:"type,omitempty"` } func (m *TreeHeader) Reset() { *m = TreeHeader{} } @@ -74,7 +100,15 @@ func (m *TreeHeader) GetIsWorkspace() bool { return false } +func (m *TreeHeader) GetType() TreeHeaderTreeType { + if m != nil { + return m.Type + } + return TreeHeader_ACLTree +} + func init() { + proto.RegisterEnum("tree.TreeHeaderTreeType", TreeHeaderTreeType_name, TreeHeaderTreeType_value) proto.RegisterType((*TreeHeader)(nil), "tree.TreeHeader") } @@ -83,18 +117,21 @@ func init() { } var fileDescriptor_e7d760b855878644 = []byte{ - // 165 bytes of a gzipped FileDescriptorProto + // 220 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0x29, 0xc8, 0x4e, 0xd7, 0x4f, 0x4c, 0xce, 0xd1, 0x2f, 0x29, 0x4a, 0x4d, 0x2d, 0x2e, 0xc9, 0x2f, 0x4a, 0x4c, 0x4f, 0x05, 0xb3, 0x0b, 0x92, 0xf4, 0x0b, 0x8a, 0xf2, 0x4b, 0xf2, 0x8b, 0xc1, 0x3c, 0x3d, 0x30, 0x5b, 0x88, - 0x05, 0xc4, 0x56, 0x0a, 0xe1, 0xe2, 0x0a, 0x29, 0x4a, 0x4d, 0xf5, 0x48, 0x4d, 0x4c, 0x49, 0x2d, - 0x12, 0x52, 0xe1, 0xe2, 0x4d, 0xcb, 0x2c, 0x2a, 0x2e, 0x71, 0xce, 0x48, 0xcc, 0x4b, 0x4f, 0xf5, - 0x4c, 0x91, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x0c, 0x42, 0x15, 0x14, 0x52, 0xe0, 0xe2, 0xce, 0x2c, - 0x0e, 0xcf, 0x2f, 0xca, 0x2e, 0x2e, 0x48, 0x4c, 0x4e, 0x95, 0x60, 0x52, 0x60, 0xd4, 0xe0, 0x08, - 0x42, 0x16, 0x72, 0x52, 0x38, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, - 0x18, 0x27, 0x3c, 0x96, 0x63, 0xb8, 0xf0, 0x58, 0x8e, 0xe1, 0xc6, 0x63, 0x39, 0x86, 0x28, 0x36, - 0x88, 0x7b, 0x92, 0xd8, 0xc0, 0x8e, 0x30, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x09, 0x4f, 0xc6, - 0xec, 0xb4, 0x00, 0x00, 0x00, + 0x05, 0xc4, 0x56, 0x5a, 0xc9, 0xc8, 0xc5, 0x15, 0x52, 0x94, 0x9a, 0xea, 0x91, 0x9a, 0x98, 0x92, + 0x5a, 0x24, 0xa4, 0xc2, 0xc5, 0x9b, 0x96, 0x59, 0x54, 0x5c, 0xe2, 0x9c, 0x91, 0x98, 0x97, 0x9e, + 0xea, 0x99, 0x22, 0xc1, 0xa8, 0xc0, 0xa8, 0xc1, 0x19, 0x84, 0x2a, 0x28, 0xa4, 0xc0, 0xc5, 0x9d, + 0x59, 0x1c, 0x9e, 0x5f, 0x94, 0x5d, 0x5c, 0x90, 0x98, 0x9c, 0x2a, 0xc1, 0xa4, 0xc0, 0xa8, 0xc1, + 0x11, 0x84, 0x2c, 0x24, 0xa4, 0xcb, 0xc5, 0x52, 0x52, 0x59, 0x90, 0x2a, 0xc1, 0xac, 0xc0, 0xa8, + 0xc1, 0x67, 0x24, 0xa9, 0x07, 0xb6, 0x17, 0x61, 0x0f, 0x98, 0x19, 0x52, 0x59, 0x90, 0x1a, 0x04, + 0x56, 0xa6, 0xa4, 0xc2, 0xc5, 0x01, 0x13, 0x11, 0xe2, 0xe6, 0x62, 0x77, 0x74, 0xf6, 0x01, 0x71, + 0x05, 0x18, 0x40, 0x1c, 0x97, 0xfc, 0x64, 0x30, 0x87, 0xd1, 0x49, 0xe1, 0xc4, 0x23, 0x39, 0xc6, + 0x0b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, 0x92, 0x63, 0x9c, 0xf0, 0x58, 0x8e, 0xe1, 0xc2, 0x63, 0x39, + 0x86, 0x1b, 0x8f, 0xe5, 0x18, 0xa2, 0xd8, 0x20, 0xbe, 0x4c, 0x62, 0x03, 0x7b, 0xcd, 0x18, 0x10, + 0x00, 0x00, 0xff, 0xff, 0x72, 0x29, 0xbc, 0x0e, 0x0a, 0x01, 0x00, 0x00, } func (m *TreeHeader) Marshal() (dAtA []byte, err error) { @@ -117,6 +154,11 @@ func (m *TreeHeader) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.Type != 0 { + i = encodeVarintTree(dAtA, i, uint64(m.Type)) + i-- + dAtA[i] = 0x18 + } if m.IsWorkspace { i-- if m.IsWorkspace { @@ -161,6 +203,9 @@ func (m *TreeHeader) Size() (n int) { if m.IsWorkspace { n += 2 } + if m.Type != 0 { + n += 1 + sovTree(uint64(m.Type)) + } return n } @@ -251,6 +296,25 @@ func (m *TreeHeader) Unmarshal(dAtA []byte) error { } } m.IsWorkspace = bool(v != 0) + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) + } + m.Type = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTree + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Type |= TreeHeaderTreeType(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTree(dAtA[iNdEx:])