diff --git a/client/clientspace/service.go b/client/clientspace/service.go index 26497d94..fdb90e51 100644 --- a/client/clientspace/service.go +++ b/client/clientspace/service.go @@ -42,7 +42,7 @@ func (s *service) Init(a *app.App) (err error) { s.spaceStorageProvider = a.MustComponent(storage.CName).(storage.SpaceStorageProvider) s.spaceCache = ocache.New( func(ctx context.Context, id string) (value ocache.Object, err error) { - return s.commonSpace.GetSpace(ctx, id) + return s.commonSpace.NewSpace(ctx, id) }, ocache.WithLogger(log.Sugar()), ocache.WithGCPeriod(time.Minute), diff --git a/client/storage/liststorage.go b/client/storage/liststorage.go index 40d46e38..fbe10d35 100644 --- a/client/storage/liststorage.go +++ b/client/storage/liststorage.go @@ -77,7 +77,7 @@ func createListStorage(spaceId string, db *badger.DB, txn *badger.Txn, root *acl return } -func (l *listStorage) ID() string { +func (l *listStorage) Id() string { return l.id } diff --git a/client/storage/liststorage_test.go b/client/storage/liststorage_test.go index 6afa676c..4c4df686 100644 --- a/client/storage/liststorage_test.go +++ b/client/storage/liststorage_test.go @@ -10,7 +10,7 @@ import ( ) func testList(t *testing.T, store storage.ListStorage, root *aclrecordproto.RawACLRecordWithId, head string) { - require.Equal(t, store.ID(), root.Id) + require.Equal(t, store.Id(), root.Id) aclRoot, err := store.Root() require.NoError(t, err) diff --git a/client/storage/spacestorage.go b/client/storage/spacestorage.go index 58f43482..8d41b298 100644 --- a/client/storage/spacestorage.go +++ b/client/storage/spacestorage.go @@ -3,7 +3,7 @@ package storage import ( "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" spacestorage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" - storage2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage" + storage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage" "github.com/dgraph-io/badger/v3" "sync" ) @@ -12,7 +12,7 @@ type spaceStorage struct { spaceId string objDb *badger.DB keys spaceKeys - aclStorage storage2.ListStorage + aclStorage storage.ListStorage header *spacesyncproto.RawSpaceHeaderWithId mx sync.Mutex } @@ -77,15 +77,15 @@ func createSpaceStorage(db *badger.DB, payload spacestorage.SpaceStorageCreatePa return } -func (s *spaceStorage) ID() string { +func (s *spaceStorage) Id() string { return s.spaceId } -func (s *spaceStorage) TreeStorage(id string) (storage2.TreeStorage, error) { +func (s *spaceStorage) TreeStorage(id string) (storage.TreeStorage, error) { return newTreeStorage(s.objDb, s.spaceId, id) } -func (s *spaceStorage) CreateTreeStorage(payload storage2.TreeStorageCreatePayload) (ts storage2.TreeStorage, err error) { +func (s *spaceStorage) CreateTreeStorage(payload storage.TreeStorageCreatePayload) (ts storage.TreeStorage, err error) { // we have mutex here, so we prevent overwriting the heads of a tree on concurrent creation s.mx.Lock() defer s.mx.Unlock() @@ -93,7 +93,7 @@ func (s *spaceStorage) CreateTreeStorage(payload storage2.TreeStorageCreatePaylo return createTreeStorage(s.objDb, s.spaceId, payload) } -func (s *spaceStorage) ACLStorage() (storage2.ListStorage, error) { +func (s *spaceStorage) ACLStorage() (storage.ListStorage, error) { return s.aclStorage, nil } diff --git a/client/storage/treestorage.go b/client/storage/treestorage.go index 25c49192..2c555555 100644 --- a/client/storage/treestorage.go +++ b/client/storage/treestorage.go @@ -2,7 +2,7 @@ package storage import ( "context" - storage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto" "github.com/dgraph-io/badger/v3" ) @@ -88,7 +88,7 @@ func createTreeStorage(db *badger.DB, spaceId string, payload storage.TreeStorag return } -func (t *treeStorage) ID() string { +func (t *treeStorage) Id() string { return t.id } diff --git a/client/storage/treestorage_test.go b/client/storage/treestorage_test.go index e2a3bcad..84b422d5 100644 --- a/client/storage/treestorage_test.go +++ b/client/storage/treestorage_test.go @@ -27,7 +27,7 @@ type fixture struct { } func testTreePayload(t *testing.T, store storage.TreeStorage, payload storage.TreeStorageCreatePayload) { - require.Equal(t, payload.RootRawChange.Id, store.ID()) + require.Equal(t, payload.RootRawChange.Id, store.Id()) root, err := store.Root() require.NoError(t, err) diff --git a/common/commonspace/service.go b/common/commonspace/service.go index c5e94298..f9ca00d8 100644 --- a/common/commonspace/service.go +++ b/common/commonspace/service.go @@ -10,7 +10,7 @@ import ( "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter" - config2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/config" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/config" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/pool" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf" @@ -28,13 +28,13 @@ func New() Service { type Service interface { DeriveSpace(ctx context.Context, payload SpaceDerivePayload) (string, error) CreateSpace(ctx context.Context, payload SpaceCreatePayload) (string, error) - GetSpace(ctx context.Context, id string) (sp Space, err error) + NewSpace(ctx context.Context, id string) (sp Space, err error) AddSpace(ctx context.Context, spaceDescription SpaceDescription) (err error) app.Component } type service struct { - config config2.Space + config config.Space account account.Service configurationService nodeconf.Service storageProvider storage.SpaceStorageProvider @@ -43,7 +43,7 @@ type service struct { } func (s *service) Init(a *app.App) (err error) { - s.config = a.MustComponent(config2.CName).(*config2.Config).Space + s.config = a.MustComponent(config.CName).(*config.Config).Space s.account = a.MustComponent(account.CName).(account.Service) s.storageProvider = a.MustComponent(storage.CName).(storage.SpaceStorageProvider) s.configurationService = a.MustComponent(nodeconf.CName).(nodeconf.Service) @@ -56,9 +56,7 @@ func (s *service) Name() (name string) { return CName } -func (s *service) CreateSpace( - ctx context.Context, - payload SpaceCreatePayload) (id string, err error) { +func (s *service) CreateSpace(ctx context.Context, payload SpaceCreatePayload) (id string, err error) { storageCreate, err := storagePayloadForSpaceCreate(payload) if err != nil { return @@ -68,12 +66,10 @@ func (s *service) CreateSpace( return } - return store.ID(), nil + return store.Id(), nil } -func (s *service) DeriveSpace( - ctx context.Context, - payload SpaceDerivePayload) (id string, err error) { +func (s *service) DeriveSpace(ctx context.Context, payload SpaceDerivePayload) (id string, err error) { storageCreate, err := storagePayloadForSpaceDerive(payload) if err != nil { return @@ -83,7 +79,7 @@ func (s *service) DeriveSpace( return } - return store.ID(), nil + return store.Id(), nil } func (s *service) AddSpace(ctx context.Context, spaceDescription SpaceDescription) (err error) { @@ -116,7 +112,7 @@ func (s *service) AddSpace(ctx context.Context, spaceDescription SpaceDescriptio return } -func (s *service) GetSpace(ctx context.Context, id string) (Space, error) { +func (s *service) NewSpace(ctx context.Context, id string) (Space, error) { st, err := s.storageProvider.SpaceStorage(id) if err != nil { if err != spacesyncproto.ErrSpaceMissing { @@ -143,32 +139,23 @@ func (s *service) GetSpace(ctx context.Context, id string) (Space, error) { configuration: lastConfiguration, storage: st, } - if err := sp.Init(ctx); err != nil { - return nil, err - } return sp, nil } func (s *service) getSpaceStorageFromRemote(ctx context.Context, id string) (st storage.SpaceStorage, err error) { var p peer.Peer - peerId, err := syncservice.GetPeerIdFromStreamContext(ctx) - if err == nil { - p, err = s.pool.Dial(ctx, peerId) - if err != nil { - return - } - } else { - lastConfiguration := s.configurationService.GetLast() - // for nodes we always get remote space only if we have id in the context - if lastConfiguration.IsResponsible(id) { - err = spacesyncproto.ErrSpaceMissing - return - } - p, err = s.pool.DialOneOf(ctx, lastConfiguration.NodeIds(id)) - if err != nil { - return - } + lastConfiguration := s.configurationService.GetLast() + // for nodes we always get remote space only if we have id in the context + if lastConfiguration.IsResponsible(id) { + err = spacesyncproto.ErrSpaceMissing + return } + + p, err = s.pool.DialOneOf(ctx, lastConfiguration.NodeIds(id)) + if err != nil { + return + } + cl := spacesyncproto.NewDRPCSpaceClient(p) res, err := cl.PullSpace(ctx, &spacesyncproto.PullSpaceRequest{Id: id}) if err != nil { diff --git a/common/commonspace/space.go b/common/commonspace/space.go index 367c1296..8b72008d 100644 --- a/common/commonspace/space.go +++ b/common/commonspace/space.go @@ -15,9 +15,10 @@ import ( "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/list" - tree "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/encryptionkey" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/signingkey" + "github.com/zeebo/errs" "go.uber.org/zap" "sync" "sync/atomic" @@ -58,6 +59,8 @@ func NewSpaceId(id string, repKey uint64) string { type Space interface { Id() string + Init(ctx context.Context) error + StoredIds() []string Description() SpaceDescription @@ -206,7 +209,18 @@ func (s *space) Close() error { s.isClosed.Store(true) log.With(zap.String("id", s.id)).Debug("space closed") }() - s.diffService.Close() - s.syncService.Close() - return s.storage.Close() + var mError errs.Group + if err := s.diffService.Close(); err != nil { + mError.Add(err) + } + if err := s.syncService.Close(); err != nil { + mError.Add(err) + } + if err := s.aclList.Close(); err != nil { + mError.Add(err) + } + if err := s.storage.Close(); err != nil { + mError.Add(err) + } + return mError.Err() } diff --git a/common/commonspace/storage/mock_storage/mock_storage.go b/common/commonspace/storage/mock_storage/mock_storage.go index fb76ad05..419c61fa 100644 --- a/common/commonspace/storage/mock_storage/mock_storage.go +++ b/common/commonspace/storage/mock_storage/mock_storage.go @@ -162,18 +162,18 @@ func (mr *MockSpaceStorageMockRecorder) CreateTreeStorage(arg0 interface{}) *gom return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateTreeStorage", reflect.TypeOf((*MockSpaceStorage)(nil).CreateTreeStorage), arg0) } -// ID mocks base method. -func (m *MockSpaceStorage) ID() string { +// Id mocks base method. +func (m *MockSpaceStorage) Id() string { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ID") + ret := m.ctrl.Call(m, "Id") ret0, _ := ret[0].(string) return ret0 } -// ID indicates an expected call of ID. -func (mr *MockSpaceStorageMockRecorder) ID() *gomock.Call { +// Id indicates an expected call of Id. +func (mr *MockSpaceStorageMockRecorder) Id() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockSpaceStorage)(nil).ID)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Id", reflect.TypeOf((*MockSpaceStorage)(nil).Id)) } // SpaceHeader mocks base method. diff --git a/common/commonspace/storage/storage.go b/common/commonspace/storage/storage.go index a469a4b1..a18b9c16 100644 --- a/common/commonspace/storage/storage.go +++ b/common/commonspace/storage/storage.go @@ -6,7 +6,7 @@ import ( "github.com/anytypeio/go-anytype-infrastructure-experiments/common/app" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto" - storage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage" ) const CName = "commonspace.storage" @@ -16,7 +16,7 @@ var ErrSpaceStorageMissing = errors.New("space storage missing") type SpaceStorage interface { storage.Provider - ID() string + Id() string ACLStorage() (storage.ListStorage, error) SpaceHeader() (*spacesyncproto.RawSpaceHeaderWithId, error) StoredIds() ([]string, error) diff --git a/common/commonspace/syncacl/syncaclhandler.go b/common/commonspace/syncacl/syncaclhandler.go new file mode 100644 index 00000000..feb78e07 --- /dev/null +++ b/common/commonspace/syncacl/syncaclhandler.go @@ -0,0 +1,31 @@ +package syncacl + +import ( + "context" + "fmt" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/list" +) + +type syncAclHandler struct { + acl list.ACLList +} + +func (s *syncAclHandler) HandleMessage(ctx context.Context, senderId string, req *spacesyncproto.ObjectSyncMessage) (err error) { + aclMsg := &aclrecordproto.ACLSyncMessage{} + if err = aclMsg.Unmarshal(req.Payload); err != nil { + return + } + content := aclMsg.GetContent() + switch { + case content.GetAddRecords() != nil: + return s.handleAddRecords(ctx, senderId, content.GetAddRecords()) + default: + return fmt.Errorf("unexpected aclSync message: %T", content.Value) + } +} + +func (s *syncAclHandler) handleAddRecords(ctx context.Context, senderId string, addRecord *aclrecordproto.ACLAddRecords) (err error) { + return +} diff --git a/common/pkg/acl/aclrecordproto/aclrecord.pb.go b/common/pkg/acl/aclrecordproto/aclrecord.pb.go index bca4e5d8..ea582a27 100644 --- a/common/pkg/acl/aclrecordproto/aclrecord.pb.go +++ b/common/pkg/acl/aclrecordproto/aclrecord.pb.go @@ -51,8 +51,10 @@ func (ACLUserPermissions) EnumDescriptor() ([]byte, []int) { } type RawACLRecord struct { - Payload []byte `protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"` - Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"` + Payload []byte `protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"` + Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"` + AcceptorIdentity []byte `protobuf:"bytes,3,opt,name=acceptorIdentity,proto3" json:"acceptorIdentity,omitempty"` + AcceptorSignature []byte `protobuf:"bytes,4,opt,name=acceptorSignature,proto3" json:"acceptorSignature,omitempty"` } func (m *RawACLRecord) Reset() { *m = RawACLRecord{} } @@ -102,6 +104,20 @@ func (m *RawACLRecord) GetSignature() []byte { return nil } +func (m *RawACLRecord) GetAcceptorIdentity() []byte { + if m != nil { + return m.AcceptorIdentity + } + return nil +} + +func (m *RawACLRecord) GetAcceptorSignature() []byte { + if m != nil { + return m.AcceptorSignature + } + return nil +} + type RawACLRecordWithId struct { Payload []byte `protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"` Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` @@ -987,6 +1003,168 @@ func (m *ACLUserPermissionChange) GetPermissions() ACLUserPermissions { return ACLUserPermissions_Admin } +type ACLSyncMessage struct { + Content *ACLSyncContentValue `protobuf:"bytes,2,opt,name=content,proto3" json:"content,omitempty"` +} + +func (m *ACLSyncMessage) Reset() { *m = ACLSyncMessage{} } +func (m *ACLSyncMessage) String() string { return proto.CompactTextString(m) } +func (*ACLSyncMessage) ProtoMessage() {} +func (*ACLSyncMessage) Descriptor() ([]byte, []int) { + return fileDescriptor_14abe0d1b4206d54, []int{14} +} +func (m *ACLSyncMessage) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ACLSyncMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ACLSyncMessage.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ACLSyncMessage) XXX_Merge(src proto.Message) { + xxx_messageInfo_ACLSyncMessage.Merge(m, src) +} +func (m *ACLSyncMessage) XXX_Size() int { + return m.Size() +} +func (m *ACLSyncMessage) XXX_DiscardUnknown() { + xxx_messageInfo_ACLSyncMessage.DiscardUnknown(m) +} + +var xxx_messageInfo_ACLSyncMessage proto.InternalMessageInfo + +func (m *ACLSyncMessage) GetContent() *ACLSyncContentValue { + if m != nil { + return m.Content + } + return nil +} + +// ACLSyncContentValue provides different types for acl sync +type ACLSyncContentValue struct { + // Types that are valid to be assigned to Value: + // + // *ACLSyncContentValue_AddRecords + Value isACLSyncContentValue_Value `protobuf_oneof:"value"` +} + +func (m *ACLSyncContentValue) Reset() { *m = ACLSyncContentValue{} } +func (m *ACLSyncContentValue) String() string { return proto.CompactTextString(m) } +func (*ACLSyncContentValue) ProtoMessage() {} +func (*ACLSyncContentValue) Descriptor() ([]byte, []int) { + return fileDescriptor_14abe0d1b4206d54, []int{15} +} +func (m *ACLSyncContentValue) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ACLSyncContentValue) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ACLSyncContentValue.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ACLSyncContentValue) XXX_Merge(src proto.Message) { + xxx_messageInfo_ACLSyncContentValue.Merge(m, src) +} +func (m *ACLSyncContentValue) XXX_Size() int { + return m.Size() +} +func (m *ACLSyncContentValue) XXX_DiscardUnknown() { + xxx_messageInfo_ACLSyncContentValue.DiscardUnknown(m) +} + +var xxx_messageInfo_ACLSyncContentValue proto.InternalMessageInfo + +type isACLSyncContentValue_Value interface { + isACLSyncContentValue_Value() + MarshalTo([]byte) (int, error) + Size() int +} + +type ACLSyncContentValue_AddRecords struct { + AddRecords *ACLAddRecords `protobuf:"bytes,1,opt,name=addRecords,proto3,oneof" json:"addRecords,omitempty"` +} + +func (*ACLSyncContentValue_AddRecords) isACLSyncContentValue_Value() {} + +func (m *ACLSyncContentValue) GetValue() isACLSyncContentValue_Value { + if m != nil { + return m.Value + } + return nil +} + +func (m *ACLSyncContentValue) GetAddRecords() *ACLAddRecords { + if x, ok := m.GetValue().(*ACLSyncContentValue_AddRecords); ok { + return x.AddRecords + } + return nil +} + +// XXX_OneofWrappers is for the internal use of the proto package. +func (*ACLSyncContentValue) XXX_OneofWrappers() []interface{} { + return []interface{}{ + (*ACLSyncContentValue_AddRecords)(nil), + } +} + +type ACLAddRecords struct { + Records []*RawACLRecordWithId `protobuf:"bytes,1,rep,name=records,proto3" json:"records,omitempty"` +} + +func (m *ACLAddRecords) Reset() { *m = ACLAddRecords{} } +func (m *ACLAddRecords) String() string { return proto.CompactTextString(m) } +func (*ACLAddRecords) ProtoMessage() {} +func (*ACLAddRecords) Descriptor() ([]byte, []int) { + return fileDescriptor_14abe0d1b4206d54, []int{16} +} +func (m *ACLAddRecords) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ACLAddRecords) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ACLAddRecords.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ACLAddRecords) XXX_Merge(src proto.Message) { + xxx_messageInfo_ACLAddRecords.Merge(m, src) +} +func (m *ACLAddRecords) XXX_Size() int { + return m.Size() +} +func (m *ACLAddRecords) XXX_DiscardUnknown() { + xxx_messageInfo_ACLAddRecords.DiscardUnknown(m) +} + +var xxx_messageInfo_ACLAddRecords proto.InternalMessageInfo + +func (m *ACLAddRecords) GetRecords() []*RawACLRecordWithId { + if m != nil { + return m.Records + } + return nil +} + func init() { proto.RegisterEnum("aclrecord.ACLUserPermissions", ACLUserPermissions_name, ACLUserPermissions_value) proto.RegisterType((*RawACLRecord)(nil), "aclrecord.RawACLRecord") @@ -1004,6 +1182,9 @@ func init() { proto.RegisterType((*ACLUserRemove)(nil), "aclrecord.ACLUserRemove") proto.RegisterType((*ACLReadKeyReplace)(nil), "aclrecord.ACLReadKeyReplace") proto.RegisterType((*ACLUserPermissionChange)(nil), "aclrecord.ACLUserPermissionChange") + proto.RegisterType((*ACLSyncMessage)(nil), "aclrecord.ACLSyncMessage") + proto.RegisterType((*ACLSyncContentValue)(nil), "aclrecord.ACLSyncContentValue") + proto.RegisterType((*ACLAddRecords)(nil), "aclrecord.ACLAddRecords") } func init() { @@ -1011,61 +1192,67 @@ func init() { } var fileDescriptor_14abe0d1b4206d54 = []byte{ - // 854 bytes of a gzipped FileDescriptorProto + // 954 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0x4f, 0x6f, 0x1b, 0x45, - 0x14, 0xdf, 0x59, 0x3b, 0x71, 0xf6, 0xd9, 0x6d, 0xdc, 0x11, 0xa4, 0xab, 0xa8, 0x58, 0xd6, 0x8a, - 0x83, 0x55, 0x81, 0x0b, 0x06, 0xa9, 0x28, 0x07, 0x90, 0x6b, 0x5a, 0x39, 0x24, 0x87, 0x6a, 0x02, - 0x14, 0x71, 0x9b, 0xee, 0x8e, 0xe2, 0x51, 0xed, 0xdd, 0xd5, 0xec, 0xd8, 0xc8, 0x47, 0xce, 0x5c, - 0xe0, 0x23, 0xf0, 0x41, 0xb8, 0x23, 0x71, 0xe9, 0x05, 0xc4, 0x11, 0x25, 0x1f, 0x83, 0x0b, 0x9a, - 0xd9, 0xff, 0xbb, 0xb6, 0x45, 0x25, 0xab, 0x87, 0xc4, 0xf3, 0xde, 0xfb, 0xbd, 0xe7, 0xdf, 0xfc, - 0xe6, 0xcd, 0x1b, 0xc3, 0x87, 0xe1, 0xab, 0xeb, 0x47, 0xd4, 0x9d, 0xab, 0x3f, 0xc1, 0xdc, 0x40, - 0x78, 0xa1, 0x08, 0x64, 0xf0, 0x48, 0xff, 0x8f, 0x72, 0xef, 0x50, 0x3b, 0xb0, 0x95, 0x39, 0x9c, - 0x67, 0xd0, 0x21, 0xf4, 0x87, 0xf1, 0xe4, 0x92, 0x68, 0x1b, 0xdb, 0xd0, 0x0a, 0xe9, 0x7a, 0x1e, - 0x50, 0xcf, 0x46, 0x7d, 0x34, 0xe8, 0x90, 0xd4, 0xc4, 0x0f, 0xc0, 0x8a, 0xf8, 0xb5, 0x4f, 0xe5, - 0x52, 0x30, 0xdb, 0xd4, 0xb1, 0xdc, 0xe1, 0x7c, 0x0e, 0xb8, 0x58, 0xe7, 0x05, 0x97, 0xb3, 0xf3, - 0x5d, 0xd5, 0xee, 0x82, 0xc9, 0x3d, 0x5d, 0xc6, 0x22, 0x26, 0xf7, 0x9c, 0x5f, 0x11, 0x58, 0x39, - 0x8b, 0x13, 0x38, 0x0c, 0x05, 0x5b, 0x9d, 0xc7, 0x69, 0x16, 0x49, 0x2c, 0x7c, 0x0a, 0x47, 0xdc, - 0x63, 0xbe, 0xe4, 0x72, 0x9d, 0x50, 0xc8, 0x6c, 0x8c, 0xa1, 0xe9, 0x51, 0x49, 0xed, 0x86, 0xf6, - 0xeb, 0x35, 0x1e, 0x02, 0x76, 0x97, 0x42, 0x30, 0x5f, 0x12, 0x46, 0xbd, 0x0b, 0xb6, 0x9e, 0xd2, - 0x68, 0x66, 0x37, 0xfb, 0x68, 0xd0, 0x24, 0x1b, 0x22, 0x6a, 0x8f, 0x92, 0x2f, 0x58, 0x24, 0xe9, - 0x22, 0xb4, 0x0f, 0xfa, 0x68, 0xd0, 0x20, 0xb9, 0xc3, 0xf9, 0xc9, 0x84, 0x96, 0xe2, 0x18, 0x04, - 0xb2, 0xc4, 0x04, 0x55, 0x98, 0xbc, 0x0f, 0x77, 0x98, 0xef, 0x8a, 0x75, 0x28, 0x79, 0xe0, 0x5f, - 0xb0, 0x94, 0x6a, 0xd9, 0xa9, 0xb4, 0x89, 0x42, 0xea, 0xb2, 0x73, 0x4f, 0x53, 0xb6, 0x48, 0x6a, - 0xe2, 0x87, 0xd0, 0x4d, 0xa0, 0xcc, 0x4b, 0xd8, 0x69, 0xce, 0x1d, 0x52, 0xf3, 0x2b, 0xac, 0xc7, - 0x04, 0x5f, 0x51, 0x55, 0xf6, 0xca, 0x9d, 0xb1, 0x05, 0xd3, 0xc4, 0x2d, 0x52, 0xf3, 0x6f, 0x51, - 0xe3, 0xf0, 0xff, 0xa9, 0xd1, 0xaa, 0xaa, 0xf1, 0xa7, 0x09, 0xc7, 0xe3, 0xc9, 0xe5, 0x24, 0xf0, - 0x25, 0xf3, 0xe5, 0xb7, 0x74, 0xbe, 0x64, 0xf8, 0x63, 0x68, 0x2d, 0x23, 0x26, 0xc6, 0x5e, 0x7c, - 0x70, 0xed, 0xd1, 0xbb, 0xc3, 0xbc, 0xf7, 0xc6, 0x93, 0xcb, 0x6f, 0xe2, 0xe0, 0xd4, 0x20, 0x29, - 0x0e, 0x9f, 0x01, 0xa8, 0x25, 0x61, 0x8b, 0x60, 0x15, 0xf7, 0x55, 0x7b, 0x64, 0xd7, 0xb3, 0xe2, - 0xf8, 0xd4, 0x20, 0x05, 0x34, 0xfe, 0x0e, 0xde, 0x51, 0xd6, 0x73, 0x26, 0x16, 0x3c, 0x8a, 0x78, - 0xe0, 0x4f, 0x66, 0xd4, 0xbf, 0x66, 0x5a, 0xcf, 0xf6, 0xc8, 0xa9, 0x57, 0xa9, 0x22, 0xa7, 0x06, - 0xd9, 0x58, 0x21, 0x65, 0x75, 0xee, 0xaf, 0xb8, 0x64, 0x5a, 0xfc, 0x8d, 0xac, 0xe2, 0x78, 0xca, - 0x2a, 0xb6, 0xf0, 0xa7, 0x70, 0xa4, 0xac, 0xaf, 0x02, 0xee, 0xeb, 0xa3, 0x68, 0x8f, 0x4e, 0xea, - 0x99, 0x2a, 0x3a, 0x35, 0x48, 0x86, 0x7c, 0xd2, 0x82, 0x83, 0x95, 0xd2, 0xd0, 0x79, 0xaa, 0x9b, - 0xec, 0x4b, 0xd5, 0xbe, 0x67, 0x00, 0xd4, 0x9d, 0x27, 0x0a, 0xdb, 0xa8, 0xdf, 0x18, 0xb4, 0x47, - 0xa7, 0xe5, 0x5a, 0x45, 0xf9, 0x49, 0x01, 0xed, 0xfc, 0x8b, 0xe0, 0x68, 0x3c, 0xb9, 0xbc, 0x92, - 0x54, 0x32, 0xd5, 0x91, 0x22, 0x3f, 0x58, 0x16, 0xe9, 0x5a, 0x4d, 0x52, 0x76, 0xe2, 0xc7, 0xf1, - 0xa6, 0x75, 0x4a, 0x64, 0x9b, 0xfa, 0xeb, 0xee, 0xd7, 0xa9, 0xeb, 0x38, 0x29, 0x40, 0xf1, 0x19, - 0xb4, 0xb8, 0xde, 0x7b, 0x64, 0x37, 0x74, 0x56, 0xbf, 0x9c, 0xa5, 0x61, 0xc3, 0x58, 0x9e, 0xe8, - 0xa9, 0x2f, 0xc5, 0x9a, 0xa4, 0x09, 0xa7, 0x5f, 0x43, 0xa7, 0x18, 0xc0, 0x5d, 0x68, 0xbc, 0x62, - 0xeb, 0xe4, 0xde, 0xab, 0x25, 0x1e, 0x26, 0xca, 0x6c, 0x6f, 0x8e, 0xb8, 0x00, 0x89, 0x61, 0x67, - 0xe6, 0x67, 0xc8, 0xf9, 0x05, 0x41, 0xa7, 0x48, 0x77, 0x0f, 0xf7, 0xf5, 0x0b, 0x68, 0x87, 0x59, - 0x9b, 0x44, 0xba, 0xc7, 0xee, 0x8e, 0xde, 0xdb, 0xd5, 0x63, 0x11, 0x29, 0x66, 0x38, 0xbf, 0x21, - 0x80, 0xfc, 0x0e, 0xec, 0x81, 0xd1, 0x07, 0x70, 0xaf, 0x3a, 0x0f, 0xe2, 0x03, 0xe8, 0x90, 0x7a, - 0xa0, 0xca, 0xbf, 0xf9, 0xc6, 0xfc, 0xff, 0x42, 0x70, 0xa7, 0x24, 0x38, 0x1e, 0xc0, 0x31, 0x75, - 0x5d, 0x16, 0xca, 0xe7, 0xcb, 0x97, 0x73, 0xee, 0x5e, 0xb0, 0x74, 0x27, 0x55, 0x77, 0x81, 0xea, - 0xd5, 0x7a, 0x91, 0x4e, 0x1e, 0x53, 0x4f, 0x9e, 0x7a, 0xe0, 0x6d, 0x6f, 0xec, 0x0f, 0x04, 0xed, - 0xc2, 0xb5, 0xdc, 0xc3, 0xc9, 0x64, 0xc2, 0x5c, 0x65, 0x2f, 0x66, 0xa3, 0x28, 0x4c, 0xe6, 0xc6, - 0x0e, 0x74, 0x32, 0xad, 0xf2, 0x39, 0x5f, 0xf2, 0x6d, 0x96, 0xe3, 0x60, 0x8b, 0x1c, 0x4e, 0x94, - 0x9d, 0x52, 0x32, 0x25, 0x77, 0x6d, 0xe7, 0x19, 0x1c, 0x27, 0x33, 0x80, 0xb0, 0x70, 0x4e, 0xdd, - 0xec, 0xde, 0x3f, 0x28, 0xeb, 0x47, 0x4a, 0x20, 0x52, 0x4d, 0x72, 0x7e, 0x44, 0x70, 0xaf, 0x06, - 0xdb, 0x83, 0x90, 0x9b, 0x9e, 0xc2, 0xc6, 0xe6, 0xa7, 0xd0, 0x59, 0xc1, 0xfd, 0x2d, 0x63, 0x7e, - 0x27, 0x91, 0x4a, 0xfb, 0x98, 0x6f, 0xda, 0x3e, 0x0f, 0x1f, 0x03, 0xae, 0x43, 0xb0, 0x05, 0x07, - 0x63, 0x6f, 0xc1, 0xfd, 0xae, 0x81, 0x01, 0x0e, 0x5f, 0x08, 0x2e, 0x99, 0xe8, 0x22, 0xb5, 0x56, - 0x7c, 0x99, 0xe8, 0x9a, 0x4f, 0x3e, 0xfa, 0xfd, 0xa6, 0x87, 0x5e, 0xdf, 0xf4, 0xd0, 0x3f, 0x37, - 0x3d, 0xf4, 0xf3, 0x6d, 0xcf, 0x78, 0x7d, 0xdb, 0x33, 0xfe, 0xbe, 0xed, 0x19, 0xdf, 0x9f, 0x6c, - 0xfe, 0x3d, 0xf7, 0xf2, 0x50, 0x7f, 0x7c, 0xf2, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x80, 0xdf, - 0xf6, 0x6c, 0xf0, 0x09, 0x00, 0x00, + 0x14, 0xf7, 0xac, 0x9d, 0x38, 0x7e, 0x76, 0x13, 0x67, 0x80, 0x74, 0x15, 0x15, 0x2b, 0x5a, 0x71, + 0x88, 0xaa, 0xe2, 0x82, 0x41, 0x4a, 0x95, 0x03, 0xc8, 0x35, 0x45, 0x76, 0x13, 0xa4, 0x6a, 0x02, + 0x14, 0xf5, 0x36, 0xdd, 0x1d, 0x25, 0xab, 0xda, 0xbb, 0xab, 0x99, 0xb1, 0xd1, 0x1e, 0x39, 0x73, + 0x81, 0x6f, 0x00, 0x1f, 0x84, 0x3b, 0x12, 0x97, 0x5e, 0x40, 0x1c, 0x51, 0xf2, 0x31, 0xb8, 0xa0, + 0x99, 0xd9, 0xff, 0xeb, 0x44, 0x54, 0x8a, 0x7a, 0x48, 0x32, 0xf3, 0xde, 0xef, 0x4d, 0x7e, 0xef, + 0xf7, 0xde, 0xbc, 0x59, 0xf8, 0x30, 0x7a, 0x75, 0xfe, 0x90, 0xba, 0x73, 0xf5, 0xc3, 0x99, 0x1b, + 0x72, 0x2f, 0xe2, 0xa1, 0x0c, 0x1f, 0xea, 0xdf, 0x22, 0xb7, 0x0e, 0xb5, 0x01, 0x77, 0x32, 0x83, + 0xf3, 0x0b, 0x82, 0x1e, 0xa1, 0xdf, 0x8f, 0x27, 0xa7, 0x44, 0x1b, 0xb0, 0x0d, 0xed, 0x88, 0xc6, + 0xf3, 0x90, 0x7a, 0x36, 0x3a, 0x40, 0x87, 0x3d, 0x92, 0x6e, 0xf1, 0x3d, 0xe8, 0x08, 0xff, 0x3c, + 0xa0, 0x72, 0xc9, 0x99, 0x6d, 0x69, 0x5f, 0x6e, 0xc0, 0xf7, 0xa1, 0x4f, 0x5d, 0x97, 0x45, 0x32, + 0xe4, 0x33, 0x8f, 0x05, 0xd2, 0x97, 0xb1, 0xdd, 0xd4, 0xa0, 0x9a, 0x1d, 0x3f, 0x80, 0xdd, 0xd4, + 0x76, 0x96, 0x9d, 0xd8, 0xd2, 0xe0, 0xba, 0xc3, 0xf9, 0x0c, 0x70, 0x91, 0xe1, 0x73, 0x5f, 0x5e, + 0xcc, 0x6e, 0xe2, 0xb9, 0x0d, 0x96, 0xef, 0x69, 0x82, 0x1d, 0x62, 0xf9, 0x9e, 0xf3, 0x2b, 0x82, + 0x4e, 0x9e, 0xdf, 0x1e, 0x6c, 0x46, 0x9c, 0xad, 0x66, 0x26, 0xac, 0x43, 0x92, 0x1d, 0xde, 0x87, + 0x2d, 0x3f, 0xe5, 0x6d, 0x92, 0xcb, 0xf6, 0x18, 0x43, 0xcb, 0xa3, 0x92, 0x26, 0xf9, 0xe8, 0x35, + 0x1e, 0x02, 0x76, 0x97, 0x9c, 0xb3, 0x40, 0x12, 0x46, 0xbd, 0x13, 0x16, 0x4f, 0xa9, 0xb8, 0xd0, + 0x49, 0xb4, 0xc8, 0x1a, 0x8f, 0x52, 0x4f, 0xfa, 0x0b, 0x26, 0x24, 0x5d, 0x44, 0xf6, 0xc6, 0x01, + 0x3a, 0x6c, 0x92, 0xdc, 0xe0, 0xfc, 0x68, 0x41, 0x5b, 0x71, 0x0c, 0x43, 0x59, 0x62, 0x82, 0x2a, + 0x4c, 0x3e, 0x80, 0x3b, 0x2c, 0x70, 0x79, 0x1c, 0x49, 0x3f, 0x0c, 0x4e, 0x58, 0x4a, 0xb5, 0x6c, + 0x54, 0xda, 0x88, 0x88, 0xba, 0x6c, 0xe6, 0x69, 0xca, 0x1d, 0x92, 0x6e, 0x55, 0x95, 0x12, 0x28, + 0xf3, 0x12, 0x76, 0x89, 0xf0, 0x35, 0xbb, 0xc2, 0x7a, 0x8c, 0xfb, 0x2b, 0xaa, 0x8e, 0x3d, 0x73, + 0x2f, 0xd8, 0x82, 0x69, 0xe2, 0x1d, 0x52, 0xb3, 0x5f, 0xa3, 0xc6, 0xe6, 0xff, 0x53, 0xa3, 0x5d, + 0x55, 0xe3, 0x4f, 0x0b, 0x76, 0xc6, 0x93, 0xd3, 0x49, 0x18, 0x48, 0x16, 0xc8, 0x6f, 0xe9, 0x7c, + 0xc9, 0xf0, 0xc7, 0xd0, 0x5e, 0x0a, 0xc6, 0xc7, 0x9e, 0x29, 0x5c, 0x77, 0xf4, 0xde, 0x30, 0x6f, + 0xeb, 0xf1, 0xe4, 0xf4, 0x1b, 0xe3, 0x9c, 0x36, 0x48, 0x8a, 0xc3, 0xc7, 0x00, 0x6a, 0x49, 0xd8, + 0x22, 0x5c, 0x99, 0x8e, 0xed, 0x8e, 0xec, 0x7a, 0x94, 0xf1, 0x4f, 0x1b, 0xa4, 0x80, 0xc6, 0xdf, + 0xc1, 0xbb, 0x6a, 0xf7, 0x8c, 0xf1, 0x85, 0x2f, 0x84, 0x1f, 0x06, 0x93, 0x0b, 0x1a, 0x9c, 0x33, + 0xad, 0x67, 0x77, 0xe4, 0xd4, 0x4f, 0xa9, 0x22, 0xa7, 0x0d, 0xb2, 0xf6, 0x84, 0x94, 0xd5, 0x2c, + 0x58, 0xf9, 0xd2, 0x74, 0xfd, 0x5a, 0x56, 0xc6, 0x9f, 0xb2, 0x32, 0x3b, 0xfc, 0x29, 0x6c, 0xa9, + 0xdd, 0xd3, 0xd0, 0x0f, 0x74, 0x29, 0xba, 0xa3, 0xbd, 0x7a, 0xa4, 0xf2, 0x4e, 0x1b, 0x24, 0x43, + 0x3e, 0x6e, 0xc3, 0xc6, 0x4a, 0x69, 0xe8, 0x3c, 0xd1, 0x4d, 0xf6, 0x85, 0x6a, 0xdf, 0x63, 0x00, + 0xea, 0xce, 0x13, 0x85, 0x6d, 0x74, 0xd0, 0x3c, 0xec, 0x8e, 0xf6, 0xcb, 0x67, 0x15, 0xe5, 0x27, + 0x05, 0xb4, 0xf3, 0x2f, 0x82, 0xad, 0xf1, 0xe4, 0xf4, 0x4c, 0x52, 0xc9, 0x54, 0x47, 0xf2, 0xbc, + 0xb0, 0x4c, 0xe8, 0xb3, 0x5a, 0xa4, 0x6c, 0xc4, 0x47, 0x26, 0x69, 0x1d, 0x22, 0x6c, 0x4b, 0xff, + 0xbb, 0xbb, 0x75, 0xea, 0xda, 0x4f, 0x0a, 0x50, 0x7c, 0x0c, 0x6d, 0x5f, 0xe7, 0x2e, 0xec, 0xa6, + 0x8e, 0x3a, 0x28, 0x47, 0x69, 0xd8, 0xd0, 0xc8, 0x23, 0x9e, 0x04, 0x92, 0xc7, 0x24, 0x0d, 0xd8, + 0xff, 0x1a, 0x7a, 0x45, 0x07, 0xee, 0x43, 0xf3, 0x15, 0x8b, 0x93, 0x7b, 0xaf, 0x96, 0x78, 0x98, + 0x28, 0x73, 0x7d, 0x73, 0x98, 0x03, 0x88, 0x81, 0x1d, 0x5b, 0x8f, 0x90, 0xf3, 0x33, 0x82, 0x5e, + 0x91, 0xee, 0x2d, 0xdc, 0xd7, 0xcf, 0xa1, 0x1b, 0x65, 0x6d, 0x22, 0x74, 0x8f, 0x6d, 0x8f, 0xde, + 0xbf, 0xa9, 0xc7, 0x04, 0x29, 0x46, 0x38, 0xbf, 0x21, 0x80, 0xfc, 0x0e, 0xdc, 0x02, 0xa3, 0x07, + 0xb0, 0x5b, 0x9d, 0x07, 0xa6, 0x00, 0x3d, 0x52, 0x77, 0x54, 0xf9, 0xb7, 0xde, 0x98, 0xff, 0x5f, + 0x08, 0xee, 0x94, 0x04, 0xc7, 0x87, 0xb0, 0x63, 0x5e, 0x82, 0x67, 0xcb, 0x97, 0x73, 0xdf, 0x3d, + 0x61, 0x69, 0x26, 0x55, 0x73, 0x81, 0xea, 0x59, 0xbc, 0x48, 0x27, 0x8f, 0xa5, 0x27, 0x4f, 0xdd, + 0xf1, 0xb6, 0x13, 0xfb, 0x03, 0x41, 0xb7, 0x70, 0x2d, 0x6f, 0xa1, 0x32, 0x99, 0x30, 0xf9, 0xcb, + 0xd9, 0x2c, 0x0a, 0x93, 0x99, 0xb1, 0x03, 0xbd, 0x4c, 0xab, 0x7c, 0xce, 0x97, 0x6c, 0xeb, 0xe5, + 0xd8, 0xb8, 0x46, 0x0e, 0x47, 0x64, 0x55, 0x4a, 0xa6, 0xe4, 0x4d, 0xe9, 0x7c, 0x09, 0x3b, 0xc9, + 0x0c, 0x20, 0x2c, 0x9a, 0x53, 0x37, 0xbb, 0xf7, 0xf7, 0xca, 0xfa, 0x91, 0x12, 0x88, 0x54, 0x83, + 0x9c, 0x1f, 0x10, 0xec, 0xd6, 0x60, 0xb7, 0x20, 0xe4, 0xba, 0xa7, 0xb0, 0xb9, 0xfe, 0x29, 0x74, + 0x56, 0x70, 0xf7, 0x9a, 0x31, 0x7f, 0x23, 0x91, 0x4a, 0xfb, 0x58, 0x6f, 0xdc, 0x3e, 0x4f, 0x61, + 0x5b, 0xcd, 0xb8, 0x38, 0x70, 0xbf, 0x62, 0x42, 0xd0, 0x73, 0x86, 0x1f, 0x41, 0xdb, 0x4d, 0x86, + 0xb6, 0x99, 0x59, 0x83, 0xca, 0x3c, 0x8c, 0x03, 0xb7, 0x34, 0xb8, 0x53, 0xb8, 0xf3, 0x02, 0xde, + 0x59, 0xe3, 0xd7, 0x0f, 0x81, 0xe7, 0x99, 0x8f, 0x23, 0x91, 0x3c, 0xad, 0x95, 0x39, 0x38, 0xce, + 0xfc, 0xea, 0x39, 0xca, 0xd1, 0xf9, 0xc3, 0x32, 0xd5, 0x8d, 0x91, 0xe3, 0xf0, 0x11, 0xb4, 0x79, + 0x76, 0xa4, 0x2a, 0x7a, 0x31, 0xeb, 0xfa, 0xd7, 0x1c, 0x49, 0xd1, 0xf7, 0x8f, 0x00, 0xd7, 0x45, + 0xc1, 0x1d, 0xd8, 0x18, 0x7b, 0x0b, 0x3f, 0xe8, 0x37, 0x30, 0xc0, 0xe6, 0x73, 0xee, 0x4b, 0xc6, + 0xfb, 0x48, 0xad, 0x55, 0x85, 0x18, 0xef, 0x5b, 0x8f, 0x3f, 0xfa, 0xfd, 0x72, 0x80, 0x5e, 0x5f, + 0x0e, 0xd0, 0x3f, 0x97, 0x03, 0xf4, 0xd3, 0xd5, 0xa0, 0xf1, 0xfa, 0x6a, 0xd0, 0xf8, 0xfb, 0x6a, + 0xd0, 0x78, 0xb1, 0xb7, 0xfe, 0xe3, 0xf8, 0xe5, 0xa6, 0xfe, 0xf3, 0xc9, 0x7f, 0x01, 0x00, 0x00, + 0xff, 0xff, 0xa9, 0xbd, 0x7e, 0xe0, 0x3d, 0x0b, 0x00, 0x00, } func (m *RawACLRecord) Marshal() (dAtA []byte, err error) { @@ -1088,6 +1275,20 @@ func (m *RawACLRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.AcceptorSignature) > 0 { + i -= len(m.AcceptorSignature) + copy(dAtA[i:], m.AcceptorSignature) + i = encodeVarintAclrecord(dAtA, i, uint64(len(m.AcceptorSignature))) + i-- + dAtA[i] = 0x22 + } + if len(m.AcceptorIdentity) > 0 { + i -= len(m.AcceptorIdentity) + copy(dAtA[i:], m.AcceptorIdentity) + i = encodeVarintAclrecord(dAtA, i, uint64(len(m.AcceptorIdentity))) + i-- + dAtA[i] = 0x1a + } if len(m.Signature) > 0 { i -= len(m.Signature) copy(dAtA[i:], m.Signature) @@ -1844,6 +2045,131 @@ func (m *ACLUserPermissionChange) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } +func (m *ACLSyncMessage) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ACLSyncMessage) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ACLSyncMessage) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Content != nil { + { + size, err := m.Content.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAclrecord(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + return len(dAtA) - i, nil +} + +func (m *ACLSyncContentValue) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ACLSyncContentValue) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ACLSyncContentValue) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Value != nil { + { + size := m.Value.Size() + i -= size + if _, err := m.Value.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + } + } + return len(dAtA) - i, nil +} + +func (m *ACLSyncContentValue_AddRecords) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ACLSyncContentValue_AddRecords) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.AddRecords != nil { + { + size, err := m.AddRecords.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAclrecord(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} +func (m *ACLAddRecords) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ACLAddRecords) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ACLAddRecords) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Records) > 0 { + for iNdEx := len(m.Records) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Records[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAclrecord(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func encodeVarintAclrecord(dAtA []byte, offset int, v uint64) int { offset -= sovAclrecord(v) base := offset @@ -1869,6 +2195,14 @@ func (m *RawACLRecord) Size() (n int) { if l > 0 { n += 1 + l + sovAclrecord(uint64(l)) } + l = len(m.AcceptorIdentity) + if l > 0 { + n += 1 + l + sovAclrecord(uint64(l)) + } + l = len(m.AcceptorSignature) + if l > 0 { + n += 1 + l + sovAclrecord(uint64(l)) + } return n } @@ -2231,6 +2565,58 @@ func (m *ACLUserPermissionChange) Size() (n int) { return n } +func (m *ACLSyncMessage) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Content != nil { + l = m.Content.Size() + n += 1 + l + sovAclrecord(uint64(l)) + } + return n +} + +func (m *ACLSyncContentValue) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Value != nil { + n += m.Value.Size() + } + return n +} + +func (m *ACLSyncContentValue_AddRecords) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.AddRecords != nil { + l = m.AddRecords.Size() + n += 1 + l + sovAclrecord(uint64(l)) + } + return n +} +func (m *ACLAddRecords) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Records) > 0 { + for _, e := range m.Records { + l = e.Size() + n += 1 + l + sovAclrecord(uint64(l)) + } + } + return n +} + func sovAclrecord(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -2334,6 +2720,74 @@ func (m *RawACLRecord) Unmarshal(dAtA []byte) error { m.Signature = []byte{} } iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AcceptorIdentity", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclrecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthAclrecord + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthAclrecord + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AcceptorIdentity = append(m.AcceptorIdentity[:0], dAtA[iNdEx:postIndex]...) + if m.AcceptorIdentity == nil { + m.AcceptorIdentity = []byte{} + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AcceptorSignature", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclrecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthAclrecord + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthAclrecord + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AcceptorSignature = append(m.AcceptorSignature[:0], dAtA[iNdEx:postIndex]...) + if m.AcceptorSignature == nil { + m.AcceptorSignature = []byte{} + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipAclrecord(dAtA[iNdEx:]) @@ -4562,6 +5016,261 @@ func (m *ACLUserPermissionChange) Unmarshal(dAtA []byte) error { } return nil } +func (m *ACLSyncMessage) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclrecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ACLSyncMessage: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ACLSyncMessage: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Content", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclrecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAclrecord + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAclrecord + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Content == nil { + m.Content = &ACLSyncContentValue{} + } + if err := m.Content.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAclrecord(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAclrecord + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ACLSyncContentValue) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclrecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ACLSyncContentValue: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ACLSyncContentValue: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AddRecords", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclrecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAclrecord + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAclrecord + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &ACLAddRecords{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Value = &ACLSyncContentValue_AddRecords{v} + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAclrecord(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAclrecord + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ACLAddRecords) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclrecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ACLAddRecords: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ACLAddRecords: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Records", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclrecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAclrecord + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAclrecord + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Records = append(m.Records, &RawACLRecordWithId{}) + if err := m.Records[len(m.Records)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAclrecord(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAclrecord + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipAclrecord(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/common/pkg/acl/aclrecordproto/protos/aclrecord.proto b/common/pkg/acl/aclrecordproto/protos/aclrecord.proto index bca03cd6..7fe61b89 100644 --- a/common/pkg/acl/aclrecordproto/protos/aclrecord.proto +++ b/common/pkg/acl/aclrecordproto/protos/aclrecord.proto @@ -3,64 +3,66 @@ package aclrecord; option go_package = "pkg/acl/aclrecordproto"; message RawACLRecord { - bytes payload = 1; - bytes signature = 2; + bytes payload = 1; + bytes signature = 2; + bytes acceptorIdentity = 3; + bytes acceptorSignature = 4; } message RawACLRecordWithId { - bytes payload = 1; - string id = 2; + bytes payload = 1; + string id = 2; } message ACLRecord { - string prevId = 1; - bytes identity = 2; - bytes data = 3; - uint64 currentReadKeyHash = 4; - int64 timestamp = 5; + string prevId = 1; + bytes identity = 2; + bytes data = 3; + uint64 currentReadKeyHash = 4; + int64 timestamp = 5; } message ACLRoot { - bytes identity = 1; - bytes encryptionKey = 2; - string spaceId = 3; - bytes encryptedReadKey = 4; - string derivationScheme = 5; - uint64 currentReadKeyHash = 6; - int64 timestamp = 7; + bytes identity = 1; + bytes encryptionKey = 2; + string spaceId = 3; + bytes encryptedReadKey = 4; + string derivationScheme = 5; + uint64 currentReadKeyHash = 6; + int64 timestamp = 7; } message ACLContentValue { - oneof value { - ACLUserAdd userAdd = 1; - ACLUserRemove userRemove = 2; - ACLUserPermissionChange userPermissionChange = 3; - ACLUserInvite userInvite = 4; - ACLUserJoin userJoin = 5; - } + oneof value { + ACLUserAdd userAdd = 1; + ACLUserRemove userRemove = 2; + ACLUserPermissionChange userPermissionChange = 3; + ACLUserInvite userInvite = 4; + ACLUserJoin userJoin = 5; + } } message ACLData { - repeated ACLContentValue aclContent = 1; + repeated ACLContentValue aclContent = 1; } message ACLState { - repeated uint64 readKeyHashes = 1; - repeated ACLUserState userStates = 2; - map invites = 3; + repeated uint64 readKeyHashes = 1; + repeated ACLUserState userStates = 2; + map invites = 3; } message ACLUserState { - bytes identity = 1; - bytes encryptionKey = 2; - ACLUserPermissions permissions = 3; + bytes identity = 1; + bytes encryptionKey = 2; + ACLUserPermissions permissions = 3; } message ACLUserAdd { - bytes identity = 1; - bytes encryptionKey = 2; - repeated bytes encryptedReadKeys = 3; - ACLUserPermissions permissions = 4; + bytes identity = 1; + bytes encryptionKey = 2; + repeated bytes encryptedReadKeys = 3; + ACLUserPermissions permissions = 4; } message ACLUserInvite { @@ -84,18 +86,33 @@ message ACLUserRemove { } message ACLReadKeyReplace { - bytes identity = 1; - bytes encryptionKey = 2; - bytes encryptedReadKey = 3; + bytes identity = 1; + bytes encryptionKey = 2; + bytes encryptedReadKey = 3; } message ACLUserPermissionChange { - bytes identity = 1; - ACLUserPermissions permissions = 2; + bytes identity = 1; + ACLUserPermissions permissions = 2; } enum ACLUserPermissions { - Admin = 0; - Writer = 1; - Reader = 2; + Admin = 0; + Writer = 1; + Reader = 2; } + +message ACLSyncMessage { + ACLSyncContentValue content = 2; +} + +// ACLSyncContentValue provides different types for acl sync +message ACLSyncContentValue { + oneof value { + ACLAddRecords addRecords = 1; + } +} + +message ACLAddRecords { + repeated RawACLRecordWithId records = 1; +} \ No newline at end of file diff --git a/common/pkg/acl/list/aclrecordbuilder.go b/common/pkg/acl/list/aclrecordbuilder.go index 1448d460..bb99f7bc 100644 --- a/common/pkg/acl/list/aclrecordbuilder.go +++ b/common/pkg/acl/list/aclrecordbuilder.go @@ -10,6 +10,7 @@ import ( "time" ) +// remove interface type ACLRecordBuilder interface { ConvertFromRaw(rawIdRecord *aclrecordproto.RawACLRecordWithId) (rec *ACLRecord, err error) BuildUserJoin(acceptPrivKeyBytes []byte, encSymKeyBytes []byte, state *ACLState) (rec *aclrecordproto.RawACLRecord, err error) diff --git a/common/pkg/acl/list/list.go b/common/pkg/acl/list/list.go index 6045fec4..e2f486d2 100644 --- a/common/pkg/acl/list/list.go +++ b/common/pkg/acl/list/list.go @@ -29,11 +29,13 @@ type ACLList interface { Records() []*ACLRecord ACLState() *ACLState IsAfter(first string, second string) (bool, error) - AddRawRecords(ctx context.Context, rec []*aclrecordproto.RawACLRecordWithId) (err error) Head() *ACLRecord Get(id string) (*ACLRecord, error) Iterate(iterFunc IterFunc) IterateFrom(startId string, iterFunc IterFunc) + + AddRawRecord(rawRec *aclrecordproto.RawACLRecordWithId) (added bool, err error) + Close() (err error) } @@ -53,14 +55,12 @@ type aclList struct { } func BuildACLListWithIdentity(acc *account.AccountData, storage storage.ListStorage) (ACLList, error) { - id := storage.ID() builder := newACLStateBuilderWithIdentity(acc) - return build(id, builder, newACLRecordBuilder(id, common.NewKeychain()), storage) + return build(storage.Id(), builder, newACLRecordBuilder(storage.Id(), common.NewKeychain()), storage) } func BuildACLList(storage storage.ListStorage) (ACLList, error) { - id := storage.ID() - return build(id, newACLStateBuilder(), newACLRecordBuilder(id, common.NewKeychain()), storage) + return build(storage.Id(), newACLStateBuilder(), newACLRecordBuilder(storage.Id(), common.NewKeychain()), storage) } func build(id string, stateBuilder *aclStateBuilder, recBuilder ACLRecordBuilder, storage storage.ListStorage) (list ACLList, err error) { @@ -110,6 +110,7 @@ func build(id string, stateBuilder *aclStateBuilder, recBuilder ACLRecordBuilder return } + // TODO: check if this is correct (raw model instead of unmarshalled) rootWithId, err := storage.Root() if err != nil { return @@ -124,7 +125,6 @@ func build(id string, stateBuilder *aclStateBuilder, recBuilder ACLRecordBuilder aclState: state, storage: storage, id: id, - RWMutex: sync.RWMutex{}, } return } @@ -133,6 +133,37 @@ func (a *aclList) Records() []*ACLRecord { return a.records } +func (a *aclList) AddRawRecord(rawRec *aclrecordproto.RawACLRecordWithId) (added bool, err error) { + if _, ok := a.indexes[rawRec.Id]; ok { + return + } + record, err := a.recordBuilder.ConvertFromRaw(rawRec) + if err != nil { + return + } + if err = a.aclState.applyRecord(record); err != nil { + return + } + a.records = append(a.records, record) + a.indexes[record.Id] = len(a.records) - 1 + if err = a.storage.AddRawRecord(context.Background(), rawRec); err != nil { + return + } + if err = a.storage.SetHead(rawRec.Id); err != nil { + return + } + return true, nil +} + +func (a *aclList) IsValidNext(rawRec *aclrecordproto.RawACLRecordWithId) (err error) { + _, err = a.recordBuilder.ConvertFromRaw(rawRec) + if err != nil { + return + } + // TODO: change state and add "check" method for records + return +} + func (a *aclList) ID() string { return a.id } @@ -141,40 +172,6 @@ func (a *aclList) Root() *aclrecordproto.RawACLRecordWithId { return a.root } -func (a *aclList) AddRawRecords(ctx context.Context, records []*aclrecordproto.RawACLRecordWithId) (err error) { - if len(records) == 0 { - return - } - // converting and verifying - var aclRecords []*ACLRecord - for _, rec := range records { - var record *ACLRecord - record, err = a.recordBuilder.ConvertFromRaw(rec) - if err != nil { - return - } - aclRecords = append(aclRecords, record) - } - - // trying to append them to state - err = a.stateBuilder.Append(a.aclState, aclRecords) - if err != nil { - return - } - - // saving to storage - for _, rec := range records { - err = a.storage.AddRawRecord(ctx, rec) - if err != nil { - return - } - } - - // setting new head - err = a.storage.SetHead(records[len(records)-1].Id) - return -} - func (a *aclList) ACLState() *ACLState { return a.aclState } diff --git a/common/pkg/acl/list/list_test.go b/common/pkg/acl/list/list_test.go index c4effdae..965d6221 100644 --- a/common/pkg/acl/list/list_test.go +++ b/common/pkg/acl/list/list_test.go @@ -89,3 +89,7 @@ func TestAclList_ACLState_UserJoinAndRemove(t *testing.T) { _, err = aclList.ACLState().PermissionsAtRecord(records[3].Id, idB) assert.Error(t, err, "B should have no permissions at record 3, because user should be removed") } + +func TestAclList_AddRawRecord(t *testing.T) { + +} diff --git a/common/pkg/acl/storage/inmemory.go b/common/pkg/acl/storage/inmemory.go index d3d42b1e..273f6c83 100644 --- a/common/pkg/acl/storage/inmemory.go +++ b/common/pkg/acl/storage/inmemory.go @@ -33,11 +33,10 @@ func NewInMemoryACLListStorage( root: root, head: head.Id, records: allRecords, - RWMutex: sync.RWMutex{}, }, nil } -func (t *inMemoryACLListStorage) ID() string { +func (t *inMemoryACLListStorage) Id() string { t.RLock() defer t.RUnlock() return t.id @@ -112,7 +111,7 @@ func (t *inMemoryTreeStorage) HasChange(ctx context.Context, id string) (bool, e return exists, nil } -func (t *inMemoryTreeStorage) ID() string { +func (t *inMemoryTreeStorage) Id() string { t.RLock() defer t.RUnlock() return t.id diff --git a/common/pkg/acl/storage/liststorage.go b/common/pkg/acl/storage/liststorage.go index 81bb43cc..bfe47ab9 100644 --- a/common/pkg/acl/storage/liststorage.go +++ b/common/pkg/acl/storage/liststorage.go @@ -12,7 +12,7 @@ var ErrACLExists = errors.New("acl already exists") var ErrUnknownRecord = errors.New("record doesn't exist") type ListStorage interface { - ID() string + Id() string Root() (*aclrecordproto.RawACLRecordWithId, error) Head() (string, error) SetHead(headId string) error diff --git a/common/pkg/acl/storage/mock_storage/mock_storage.go b/common/pkg/acl/storage/mock_storage/mock_storage.go index 38f8a2b2..751184a7 100644 --- a/common/pkg/acl/storage/mock_storage/mock_storage.go +++ b/common/pkg/acl/storage/mock_storage/mock_storage.go @@ -80,18 +80,18 @@ func (mr *MockListStorageMockRecorder) Head() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Head", reflect.TypeOf((*MockListStorage)(nil).Head)) } -// ID mocks base method. -func (m *MockListStorage) ID() string { +// Id mocks base method. +func (m *MockListStorage) Id() string { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ID") + ret := m.ctrl.Call(m, "Id") ret0, _ := ret[0].(string) return ret0 } -// ID indicates an expected call of ID. -func (mr *MockListStorageMockRecorder) ID() *gomock.Call { +// Id indicates an expected call of Id. +func (mr *MockListStorageMockRecorder) Id() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockListStorage)(nil).ID)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Id", reflect.TypeOf((*MockListStorage)(nil).Id)) } // Root mocks base method. @@ -205,18 +205,18 @@ func (mr *MockTreeStorageMockRecorder) Heads() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Heads", reflect.TypeOf((*MockTreeStorage)(nil).Heads)) } -// ID mocks base method. -func (m *MockTreeStorage) ID() string { +// Id mocks base method. +func (m *MockTreeStorage) Id() string { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ID") + ret := m.ctrl.Call(m, "Id") ret0, _ := ret[0].(string) return ret0 } -// ID indicates an expected call of ID. -func (mr *MockTreeStorageMockRecorder) ID() *gomock.Call { +// Id indicates an expected call of Id. +func (mr *MockTreeStorageMockRecorder) Id() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockTreeStorage)(nil).ID)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Id", reflect.TypeOf((*MockTreeStorage)(nil).Id)) } // Root mocks base method. diff --git a/common/pkg/acl/storage/treestorage.go b/common/pkg/acl/storage/treestorage.go index 751dd1d9..549e872a 100644 --- a/common/pkg/acl/storage/treestorage.go +++ b/common/pkg/acl/storage/treestorage.go @@ -6,7 +6,7 @@ import ( ) type TreeStorage interface { - ID() string + Id() string Root() (*treechangeproto.RawTreeChangeWithId, error) Heads() ([]string, error) SetHeads(heads []string) error diff --git a/common/pkg/acl/tree/changevalidator.go b/common/pkg/acl/tree/changevalidator.go index 617e610d..b4d63ea9 100644 --- a/common/pkg/acl/tree/changevalidator.go +++ b/common/pkg/acl/tree/changevalidator.go @@ -3,14 +3,14 @@ package tree import ( "fmt" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto" - list2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/list" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/list" ) type ObjectTreeValidator interface { // ValidateFullTree should always be entered while holding a read lock on ACLList - ValidateFullTree(tree *Tree, aclList list2.ACLList) error + ValidateFullTree(tree *Tree, aclList list.ACLList) error // ValidateNewChanges should always be entered while holding a read lock on ACLList - ValidateNewChanges(tree *Tree, aclList list2.ACLList, newChanges []*Change) error + ValidateNewChanges(tree *Tree, aclList list.ACLList, newChanges []*Change) error } type objectTreeValidator struct{} @@ -19,7 +19,7 @@ func newTreeValidator() ObjectTreeValidator { return &objectTreeValidator{} } -func (v *objectTreeValidator) ValidateFullTree(tree *Tree, aclList list2.ACLList) (err error) { +func (v *objectTreeValidator) ValidateFullTree(tree *Tree, aclList list.ACLList) (err error) { tree.Iterate(tree.RootId(), func(c *Change) (isContinue bool) { err = v.validateChange(tree, aclList, c) return err == nil @@ -27,7 +27,7 @@ func (v *objectTreeValidator) ValidateFullTree(tree *Tree, aclList list2.ACLList return err } -func (v *objectTreeValidator) ValidateNewChanges(tree *Tree, aclList list2.ACLList, newChanges []*Change) (err error) { +func (v *objectTreeValidator) ValidateNewChanges(tree *Tree, aclList list.ACLList, newChanges []*Change) (err error) { for _, c := range newChanges { err = v.validateChange(tree, aclList, c) if err != nil { @@ -37,9 +37,9 @@ func (v *objectTreeValidator) ValidateNewChanges(tree *Tree, aclList list2.ACLLi return } -func (v *objectTreeValidator) validateChange(tree *Tree, aclList list2.ACLList, c *Change) (err error) { +func (v *objectTreeValidator) validateChange(tree *Tree, aclList list.ACLList, c *Change) (err error) { var ( - perm list2.UserPermissionPair + perm list.UserPermissionPair state = aclList.ACLState() ) // checking if the user could write @@ -49,7 +49,7 @@ func (v *objectTreeValidator) validateChange(tree *Tree, aclList list2.ACLList, } if perm.Permission != aclrecordproto.ACLUserPermissions_Writer && perm.Permission != aclrecordproto.ACLUserPermissions_Admin { - err = list2.ErrInsufficientPermissions + err = list.ErrInsufficientPermissions return } diff --git a/common/pkg/acl/tree/objecttreefactory.go b/common/pkg/acl/tree/objecttreefactory.go index ca097505..26912377 100644 --- a/common/pkg/acl/tree/objecttreefactory.go +++ b/common/pkg/acl/tree/objecttreefactory.go @@ -126,7 +126,9 @@ func buildObjectTree(deps objectTreeDeps) (ObjectTree, error) { } } - objTree.id = objTree.treeStorage.ID() + objTree.id = objTree.treeStorage.Id() + + objTree.id = objTree.treeStorage.Id() objTree.root, err = objTree.treeStorage.Root() if err != nil { return nil, err diff --git a/common/testutil/testaccount/service.go b/common/testutil/testaccount/service.go new file mode 100644 index 00000000..7995621d --- /dev/null +++ b/common/testutil/testaccount/service.go @@ -0,0 +1,44 @@ +package testaccount + +import ( + accountService "github.com/anytypeio/go-anytype-infrastructure-experiments/common/account" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/app" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/account" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/encryptionkey" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/signingkey" +) + +// AccountTestService provides service for test purposes, generates new random account every Init +type AccountTestService struct { + acc *account.AccountData +} + +func (s *AccountTestService) Init(a *app.App) (err error) { + encKey, _, err := encryptionkey.GenerateRandomRSAKeyPair(2048) + if err != nil { + return + } + + signKey, _, err := signingkey.GenerateRandomEd25519KeyPair() + if err != nil { + return + } + ident, err := signKey.GetPublic().Raw() + if err != nil { + return + } + s.acc = &account.AccountData{ + Identity: ident, + SignKey: signKey, + EncKey: encKey, + } + return nil +} + +func (s *AccountTestService) Name() (name string) { + return accountService.CName +} + +func (s *AccountTestService) Account() *account.AccountData { + return s.acc +} diff --git a/consensus/consensusclient/client.go b/consensus/consensusclient/client.go index 9d08617b..48576dd4 100644 --- a/consensus/consensusclient/client.go +++ b/consensus/consensusclient/client.go @@ -1,3 +1,4 @@ +//go:generate mockgen -destination mock_consensusclient/mock_consensusclient.go github.com/anytypeio/go-anytype-infrastructure-experiments/consensus/consensusclient Service package consensusclient import ( diff --git a/consensus/consensusclient/client_test.go b/consensus/consensusclient/client_test.go index f27787ab..e7557d0d 100644 --- a/consensus/consensusclient/client_test.go +++ b/consensus/consensusclient/client_test.go @@ -13,6 +13,7 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "sync" "testing" "time" ) @@ -22,7 +23,7 @@ func TestService_Watch(t *testing.T) { fx := newFixture(t).run(t) defer fx.Finish() var logId = []byte{'1'} - w := &testWatcher{} + w := &testWatcher{ready: make(chan struct{})} require.NoError(t, fx.Watch(logId, w)) st := fx.testServer.waitStream(t) req, err := st.Recv() @@ -34,6 +35,7 @@ func TestService_Watch(t *testing.T) { Error: consensusproto.ErrCodes_ErrorOffset + consensusproto.ErrCodes_LogNotFound, }, })) + <-w.ready assert.Equal(t, consensuserr.ErrLogNotFound, w.err) fx.testServer.releaseStream <- nil }) @@ -188,7 +190,6 @@ func (t *testServer) AddRecord(ctx context.Context, req *consensusproto.AddRecor } func (t *testServer) WatchLog(stream consensusproto.DRPCConsensus_WatchLogStream) error { - fmt.Println("watchLog", t.watchErrOnce) if t.watchErrOnce { t.watchErrOnce = false return fmt.Errorf("error") @@ -208,14 +209,22 @@ func (t *testServer) waitStream(test *testing.T) consensusproto.DRPCConsensus_Wa } type testWatcher struct { - recs [][]*consensusproto.Record - err error + recs [][]*consensusproto.Record + err error + ready chan struct{} + once sync.Once } func (t *testWatcher) AddConsensusRecords(recs []*consensusproto.Record) { t.recs = append(t.recs, recs) + t.once.Do(func() { + close(t.ready) + }) } func (t *testWatcher) AddConsensusError(err error) { t.err = err + t.once.Do(func() { + close(t.ready) + }) } diff --git a/consensus/consensusclient/mock_consensusclient/mock_consensusclient.go b/consensus/consensusclient/mock_consensusclient/mock_consensusclient.go new file mode 100644 index 00000000..356cb927 --- /dev/null +++ b/consensus/consensusclient/mock_consensusclient/mock_consensusclient.go @@ -0,0 +1,150 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/consensus/consensusclient (interfaces: Service) + +// Package mock_consensusclient is a generated GoMock package. +package mock_consensusclient + +import ( + context "context" + reflect "reflect" + + app "github.com/anytypeio/go-anytype-infrastructure-experiments/common/app" + consensusclient "github.com/anytypeio/go-anytype-infrastructure-experiments/consensus/consensusclient" + consensusproto "github.com/anytypeio/go-anytype-infrastructure-experiments/consensus/consensusproto" + gomock "github.com/golang/mock/gomock" +) + +// MockService is a mock of Service interface. +type MockService struct { + ctrl *gomock.Controller + recorder *MockServiceMockRecorder +} + +// MockServiceMockRecorder is the mock recorder for MockService. +type MockServiceMockRecorder struct { + mock *MockService +} + +// NewMockService creates a new mock instance. +func NewMockService(ctrl *gomock.Controller) *MockService { + mock := &MockService{ctrl: ctrl} + mock.recorder = &MockServiceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockService) EXPECT() *MockServiceMockRecorder { + return m.recorder +} + +// AddLog mocks base method. +func (m *MockService) AddLog(arg0 context.Context, arg1 *consensusproto.Log) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddLog", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddLog indicates an expected call of AddLog. +func (mr *MockServiceMockRecorder) AddLog(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddLog", reflect.TypeOf((*MockService)(nil).AddLog), arg0, arg1) +} + +// AddRecord mocks base method. +func (m *MockService) AddRecord(arg0 context.Context, arg1 []byte, arg2 *consensusproto.Record) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddRecord", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddRecord indicates an expected call of AddRecord. +func (mr *MockServiceMockRecorder) AddRecord(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRecord", reflect.TypeOf((*MockService)(nil).AddRecord), arg0, arg1, arg2) +} + +// Close mocks base method. +func (m *MockService) Close(arg0 context.Context) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Close", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close. +func (mr *MockServiceMockRecorder) Close(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockService)(nil).Close), arg0) +} + +// Init mocks base method. +func (m *MockService) Init(arg0 *app.App) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Init", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Init indicates an expected call of Init. +func (mr *MockServiceMockRecorder) Init(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Init", reflect.TypeOf((*MockService)(nil).Init), arg0) +} + +// Name mocks base method. +func (m *MockService) Name() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Name") + ret0, _ := ret[0].(string) + return ret0 +} + +// Name indicates an expected call of Name. +func (mr *MockServiceMockRecorder) Name() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockService)(nil).Name)) +} + +// Run mocks base method. +func (m *MockService) Run(arg0 context.Context) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Run", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Run indicates an expected call of Run. +func (mr *MockServiceMockRecorder) Run(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Run", reflect.TypeOf((*MockService)(nil).Run), arg0) +} + +// UnWatch mocks base method. +func (m *MockService) UnWatch(arg0 []byte) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UnWatch", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// UnWatch indicates an expected call of UnWatch. +func (mr *MockServiceMockRecorder) UnWatch(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnWatch", reflect.TypeOf((*MockService)(nil).UnWatch), arg0) +} + +// Watch mocks base method. +func (m *MockService) Watch(arg0 []byte, arg1 consensusclient.Watcher) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Watch", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Watch indicates an expected call of Watch. +func (mr *MockServiceMockRecorder) Watch(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Watch", reflect.TypeOf((*MockService)(nil).Watch), arg0, arg1) +} diff --git a/consensus/consensusclient/stream.go b/consensus/consensusclient/stream.go index d3383629..d2865326 100644 --- a/consensus/consensusclient/stream.go +++ b/consensus/consensusclient/stream.go @@ -3,6 +3,7 @@ package consensusclient import ( "github.com/anytypeio/go-anytype-infrastructure-experiments/consensus/consensusproto" "github.com/cheggaaa/mb/v2" + "sync" ) func runStream(rpcStream consensusproto.DRPCConsensus_WatchLogClient) *stream { @@ -17,6 +18,7 @@ func runStream(rpcStream consensusproto.DRPCConsensus_WatchLogClient) *stream { type stream struct { rpcStream consensusproto.DRPCConsensus_WatchLogClient mb *mb.MB[*consensusproto.WatchLogEvent] + mu sync.Mutex err error } @@ -37,6 +39,8 @@ func (s *stream) WaitLogs() []*consensusproto.WatchLogEvent { } func (s *stream) Err() error { + s.mu.Lock() + defer s.mu.Unlock() return s.err } @@ -45,7 +49,9 @@ func (s *stream) readStream() { for { event, err := s.rpcStream.Recv() if err != nil { + s.mu.Lock() s.err = err + s.mu.Unlock() return } if err = s.mb.Add(event); err != nil { diff --git a/node/acl/service.go b/node/acl/service.go new file mode 100644 index 00000000..a417778c --- /dev/null +++ b/node/acl/service.go @@ -0,0 +1,134 @@ +package acl + +import ( + "context" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/account" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/app" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice/synchandler" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/cid" + "github.com/anytypeio/go-anytype-infrastructure-experiments/consensus/consensusclient" + "github.com/anytypeio/go-anytype-infrastructure-experiments/consensus/consensusproto" + "time" +) + +const CName = "node.acl" + +var log = logger.NewNamed(CName) + +func New() Service { + return &service{} +} + +type Service interface { + CreateLog(ctx context.Context, aclId string, rawRec *aclrecordproto.RawACLRecord) (firstRecId string, err error) + AddRecord(ctx context.Context, aclId string, rawRec *aclrecordproto.RawACLRecord) (id string, err error) + Watch(ctx context.Context, spaceId, aclId string, h synchandler.SyncHandler) (err error) + UnWatch(aclId string) (err error) + app.Component +} + +type service struct { + consService consensusclient.Service + account account.Service +} + +func (s *service) Init(a *app.App) (err error) { + s.consService = a.MustComponent(consensusclient.CName).(consensusclient.Service) + s.account = a.MustComponent(account.CName).(account.Service) + return +} + +func (s *service) Name() (name string) { + return CName +} + +func (s *service) CreateLog(ctx context.Context, aclId string, rawRec *aclrecordproto.RawACLRecord) (firstRecId string, err error) { + logId, err := cidToByte(aclId) + if err != nil { + return + } + recId, _, payload, err := s.signAndMarshal(rawRec) + if err != nil { + return + } + if err = s.consService.AddLog(ctx, &consensusproto.Log{ + Id: logId, + Records: []*consensusproto.Record{ + { + Id: recId, + Payload: payload, + CreatedUnix: uint64(time.Now().Unix()), + }, + }, + }); err != nil { + return + } + return cidToString(recId) +} + +func (s *service) AddRecord(ctx context.Context, aclId string, rawRec *aclrecordproto.RawACLRecord) (id string, err error) { + logId, err := cidToByte(aclId) + if err != nil { + return + } + + recId, prevId, payload, err := s.signAndMarshal(rawRec) + if err != nil { + return + } + if err = s.consService.AddRecord(ctx, logId, &consensusproto.Record{ + Id: recId, + PrevId: prevId, + Payload: payload, + CreatedUnix: uint64(time.Now().Unix()), + }); err != nil { + return + } + return cidToString(recId) +} + +func (s *service) Watch(ctx context.Context, spaceId, aclId string, h synchandler.SyncHandler) (err error) { + w, err := newWatcher(spaceId, aclId, h) + if err != nil { + return + } + if err = s.consService.Watch(w.logId, w); err != nil { + return err + } + return w.Ready(ctx) +} + +func (s *service) UnWatch(aclId string) (err error) { + logId, err := cidToByte(aclId) + if err != nil { + return + } + return s.consService.UnWatch(logId) +} + +func (s *service) signAndMarshal(rawRec *aclrecordproto.RawACLRecord) (recId, prevId, payload []byte, err error) { + var rec = &aclrecordproto.ACLRecord{} + if err = rec.Unmarshal(rawRec.Payload); err != nil { + return + } + if rec.PrevId != "" { + if prevId, err = cidToByte(rec.PrevId); err != nil { + return + } + } + rawRec.AcceptorIdentity = s.account.Account().Identity + if rawRec.AcceptorSignature, err = s.account.Account().SignKey.Sign(rawRec.Payload); err != nil { + return + } + if payload, err = rawRec.Marshal(); err != nil { + return + } + recCid, err := cid.NewCIDFromBytes(payload) + if err != nil { + return + } + recId, err = cidToByte(recCid) + return +} diff --git a/node/acl/service_test.go b/node/acl/service_test.go new file mode 100644 index 00000000..eb720d64 --- /dev/null +++ b/node/acl/service_test.go @@ -0,0 +1,195 @@ +package acl + +import ( + "context" + "fmt" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/app" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/testutil/testaccount" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/cid" + "github.com/anytypeio/go-anytype-infrastructure-experiments/consensus/consensusclient" + "github.com/anytypeio/go-anytype-infrastructure-experiments/consensus/consensusclient/mock_consensusclient" + "github.com/anytypeio/go-anytype-infrastructure-experiments/consensus/consensusproto" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "testing" + "time" +) + +var ctx = context.Background() + +func TestService_CreateLog(t *testing.T) { + fx := newFixture(t) + defer fx.Finish(t) + var clog *consensusproto.Log + fx.mockClient.EXPECT().AddLog(ctx, gomock.Any()).Do(func(ctx context.Context, l *consensusproto.Log) { + clog = l + }) + + aclId, _ := cid.NewCIDFromBytes([]byte("aclId")) + + rec := &aclrecordproto.ACLRecord{ + PrevId: "", + Identity: fx.account.Account().Identity, + Data: []byte{'1', '2', '3'}, + Timestamp: time.Now().Unix(), + } + pl, _ := rec.Marshal() + + firstRecId, err := fx.CreateLog(ctx, aclId, &aclrecordproto.RawACLRecord{ + Payload: pl, + }) + require.NoError(t, err) + aclIdBytes, _ := cidToByte(aclId) + firstRecIdBytes, _ := cidToByte(firstRecId) + assert.Equal(t, aclIdBytes, clog.Id) + assert.NotEmpty(t, firstRecIdBytes) + require.Len(t, clog.Records, 1) + + var resultRawAcl = &aclrecordproto.RawACLRecord{} + require.NoError(t, resultRawAcl.Unmarshal(clog.Records[0].Payload)) + valid, err := fx.account.Account().SignKey.GetPublic().Verify(resultRawAcl.Payload, resultRawAcl.AcceptorSignature) + require.NoError(t, err) + require.True(t, valid) +} + +func TestService_AddRecord(t *testing.T) { + fx := newFixture(t) + defer fx.Finish(t) + var clog *consensusproto.Log + fx.mockClient.EXPECT().AddLog(ctx, gomock.Any()).Do(func(ctx context.Context, l *consensusproto.Log) { + clog = l + }) + + aclId, _ := cid.NewCIDFromBytes([]byte("aclId")) + + rec := &aclrecordproto.ACLRecord{ + PrevId: "", + Identity: fx.account.Account().Identity, + Data: []byte{'1', '2', '3'}, + Timestamp: time.Now().Unix(), + } + pl, _ := rec.Marshal() + + firstRecId, err := fx.CreateLog(ctx, aclId, &aclrecordproto.RawACLRecord{ + Payload: pl, + }) + require.NoError(t, err) + aclIdBytes, _ := cidToByte(aclId) + firstRecIdBytes, _ := cidToByte(firstRecId) + assert.Equal(t, aclIdBytes, clog.Id) + assert.NotEmpty(t, firstRecIdBytes) + var addRec *consensusproto.Record + fx.mockClient.EXPECT().AddRecord(ctx, aclIdBytes, gomock.Any()).Do(func(ctx context.Context, logId []byte, rec *consensusproto.Record) { + addRec = rec + }) + rec = &aclrecordproto.ACLRecord{ + PrevId: firstRecId, + Identity: fx.account.Account().Identity, + Data: []byte{'1', '2', '3', '4'}, + Timestamp: time.Now().Unix(), + } + pl, _ = rec.Marshal() + + newRecId, err := fx.AddRecord(ctx, aclId, &aclrecordproto.RawACLRecord{ + Payload: pl, + }) + require.NoError(t, err) + assert.NotEmpty(t, newRecId) + + assert.Equal(t, firstRecIdBytes, addRec.PrevId) + +} + +func TestService_Watch(t *testing.T) { + t.Run("remote error", func(t *testing.T) { + fx := newFixture(t) + defer fx.Finish(t) + var expErr = fmt.Errorf("error") + aclId, _ := cid.NewCIDFromBytes([]byte("aclId")) + aclIdBytes, _ := cidToByte(aclId) + fx.mockClient.EXPECT().Watch(aclIdBytes, gomock.Any()).Do(func(aid []byte, w consensusclient.Watcher) { + assert.Equal(t, aclIdBytes, aid) + go func() { + time.Sleep(time.Millisecond * 10) + w.AddConsensusError(expErr) + }() + }) + + th := &testHandler{} + err := fx.Watch(ctx, "123", aclId, th) + assert.Equal(t, expErr, err) + }) + t.Run("success", func(t *testing.T) { + fx := newFixture(t) + defer fx.Finish(t) + aclId, _ := cid.NewCIDFromBytes([]byte("aclId")) + aclIdBytes, _ := cidToByte(aclId) + fx.mockClient.EXPECT().Watch(aclIdBytes, gomock.Any()).Do(func(aid []byte, w consensusclient.Watcher) { + assert.Equal(t, aclIdBytes, aid) + go func() { + time.Sleep(time.Millisecond * 10) + r1cid, _ := cid.NewCIDFromBytes([]byte("r1")) + r2cid, _ := cid.NewCIDFromBytes([]byte("r2")) + r1cidB, _ := cidToByte(r1cid) + r2cidB, _ := cidToByte(r2cid) + w.AddConsensusRecords([]*consensusproto.Record{ + { + Id: r2cidB, + PrevId: r1cidB, + Payload: []byte("p1"), + }, + { + Id: r1cidB, + Payload: []byte("p1"), + }, + }) + }() + }) + + th := &testHandler{} + err := fx.Watch(ctx, "123", aclId, th) + require.NoError(t, err) + }) +} + +func newFixture(t *testing.T) *fixture { + fx := &fixture{ + a: new(app.App), + ctrl: gomock.NewController(t), + account: &testaccount.AccountTestService{}, + } + fx.mockClient = mock_consensusclient.NewMockService(fx.ctrl) + fx.mockClient.EXPECT().Name().Return(consensusclient.CName).AnyTimes() + fx.mockClient.EXPECT().Init(gomock.Any()).AnyTimes() + fx.mockClient.EXPECT().Run(gomock.Any()).AnyTimes() + fx.mockClient.EXPECT().Close(gomock.Any()).AnyTimes() + fx.Service = New() + fx.a.Register(fx.account).Register(fx.mockClient).Register(fx.Service) + require.NoError(t, fx.a.Start(ctx)) + return fx +} + +type fixture struct { + Service + mockClient *mock_consensusclient.MockService + ctrl *gomock.Controller + a *app.App + account *testaccount.AccountTestService +} + +func (fx *fixture) Finish(t *testing.T) { + require.NoError(t, fx.a.Close(ctx)) + fx.ctrl.Finish() +} + +type testHandler struct { + req *spacesyncproto.ObjectSyncMessage +} + +func (t *testHandler) HandleMessage(ctx context.Context, senderId string, request *spacesyncproto.ObjectSyncMessage) (err error) { + t.req = request + return +} diff --git a/node/acl/util.go b/node/acl/util.go new file mode 100644 index 00000000..c6784a33 --- /dev/null +++ b/node/acl/util.go @@ -0,0 +1,19 @@ +package acl + +import "github.com/ipfs/go-cid" + +func cidToString(b []byte) (s string, err error) { + rcid, err := cid.Cast(b) + if err != nil { + return + } + return rcid.String(), nil +} + +func cidToByte(s string) (b []byte, err error) { + rcid, err := cid.Decode(s) + if err != nil { + return + } + return rcid.Bytes(), nil +} diff --git a/node/acl/util_test.go b/node/acl/util_test.go new file mode 100644 index 00000000..1ebe5fcb --- /dev/null +++ b/node/acl/util_test.go @@ -0,0 +1,16 @@ +package acl + +import ( + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/cid" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestCIDLen(t *testing.T) { + s, _ := cid.NewCIDFromBytes([]byte("some data")) + t.Log(s, len(s)) + b, _ := cidToByte(s) + t.Log(b, len(b)) + s2, _ := cidToString(b) + assert.Equal(t, s, s2) +} diff --git a/node/acl/watcher.go b/node/acl/watcher.go new file mode 100644 index 00000000..6a88cb0e --- /dev/null +++ b/node/acl/watcher.go @@ -0,0 +1,93 @@ +package acl + +import ( + "context" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice/synchandler" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto" + "github.com/anytypeio/go-anytype-infrastructure-experiments/consensus/consensusproto" + "go.uber.org/zap" + "sync" +) + +func newWatcher(spaceId, aclId string, h synchandler.SyncHandler) (w *watcher, err error) { + w = &watcher{ + aclId: aclId, + spaceId: spaceId, + handler: h, + ready: make(chan struct{}), + } + if w.logId, err = cidToByte(aclId); err != nil { + return nil, err + } + return +} + +type watcher struct { + spaceId string + aclId string + logId []byte + handler synchandler.SyncHandler + ready chan struct{} + isReady sync.Once + err error +} + +func (w *watcher) AddConsensusRecords(recs []*consensusproto.Record) { + w.isReady.Do(func() { + close(w.ready) + }) + records := make([]*aclrecordproto.RawACLRecordWithId, 0, len(recs)) + + for _, rec := range recs { + recId, err := cidToString(rec.Id) + if err != nil { + log.Error("received invalid id from consensus node", zap.Error(err)) + continue + } + records = append(records, &aclrecordproto.RawACLRecordWithId{ + Payload: rec.Payload, + Id: recId, + }) + } + + aclReq := &aclrecordproto.ACLSyncMessage{ + Content: &aclrecordproto.ACLSyncContentValue{ + Value: &aclrecordproto.ACLSyncContentValue_AddRecords{ + AddRecords: &aclrecordproto.ACLAddRecords{ + Records: records, + }, + }, + }, + } + payload, err := aclReq.Marshal() + if err != nil { + log.Error("acl payload marshal error", zap.Error(err)) + return + } + req := &spacesyncproto.ObjectSyncMessage{ + SpaceId: w.spaceId, + Payload: payload, + ObjectId: w.aclId, + } + + if err = w.handler.HandleMessage(context.TODO(), "", req); err != nil { + log.Warn("handle message error", zap.Error(err)) + } +} + +func (w *watcher) AddConsensusError(err error) { + w.isReady.Do(func() { + w.err = err + close(w.ready) + }) +} + +func (w *watcher) Ready(ctx context.Context) (err error) { + select { + case <-w.ready: + return w.err + case <-ctx.Done(): + return ctx.Err() + } +} diff --git a/node/nodespace/service.go b/node/nodespace/service.go index b5b11669..a1ad1f0a 100644 --- a/node/nodespace/service.go +++ b/node/nodespace/service.go @@ -7,7 +7,7 @@ import ( "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" - config2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/config" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/config" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/rpc/server" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ocache" "time" @@ -28,20 +28,18 @@ type Service interface { } type service struct { - conf config2.Space + conf config.Space spaceCache ocache.OCache commonSpace commonspace.Service spaceStorageProvider storage.SpaceStorageProvider } func (s *service) Init(a *app.App) (err error) { - s.conf = a.MustComponent(config2.CName).(*config2.Config).Space + s.conf = a.MustComponent(config.CName).(*config.Config).Space s.commonSpace = a.MustComponent(commonspace.CName).(commonspace.Service) s.spaceStorageProvider = a.MustComponent(storage.CName).(storage.SpaceStorageProvider) s.spaceCache = ocache.New( - func(ctx context.Context, id string) (value ocache.Object, err error) { - return s.commonSpace.GetSpace(ctx, id) - }, + s.loadSpace, ocache.WithLogger(log.Sugar()), ocache.WithGCPeriod(time.Minute), ocache.WithTTL(time.Duration(s.conf.GCTTL)*time.Second), @@ -69,6 +67,21 @@ func (s *service) AddSpace(ctx context.Context, description commonspace.SpaceDes return s.commonSpace.AddSpace(ctx, description) } +func (s *service) loadSpace(ctx context.Context, id string) (value ocache.Object, err error) { + cc, err := s.commonSpace.NewSpace(ctx, id) + if err != nil { + return + } + ns, err := newNodeSpace(cc) + if err != nil { + return + } + if err = ns.Init(ctx); err != nil { + return + } + return ns, nil +} + func (s *service) Close(ctx context.Context) (err error) { return s.spaceCache.Close() } diff --git a/node/nodespace/space.go b/node/nodespace/space.go new file mode 100644 index 00000000..a1ffe43f --- /dev/null +++ b/node/nodespace/space.go @@ -0,0 +1,24 @@ +package nodespace + +import ( + "context" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace" +) + +func newNodeSpace(cc commonspace.Space) (commonspace.Space, error) { + return &nodeSpace{cc}, nil +} + +type nodeSpace struct { + commonspace.Space +} + +func (s *nodeSpace) Init(ctx context.Context) (err error) { + // try to push acl to consensus node + // + return s.Space.Init(ctx) +} + +func (s *nodeSpace) Close() (err error) { + return s.Space.Close() +} diff --git a/node/storage/liststorage.go b/node/storage/liststorage.go index 1247b2e8..e7fa3aba 100644 --- a/node/storage/liststorage.go +++ b/node/storage/liststorage.go @@ -82,7 +82,7 @@ func createListStorage(db *pogreb.DB, root *aclrecordproto.RawACLRecordWithId) ( return } -func (l *listStorage) ID() string { +func (l *listStorage) Id() string { return l.id } diff --git a/node/storage/liststorage_test.go b/node/storage/liststorage_test.go index ae04e3af..4df253d2 100644 --- a/node/storage/liststorage_test.go +++ b/node/storage/liststorage_test.go @@ -9,7 +9,7 @@ import ( ) func testList(t *testing.T, store storage.ListStorage, root *aclrecordproto.RawACLRecordWithId, head string) { - require.Equal(t, store.ID(), root.Id) + require.Equal(t, store.Id(), root.Id) aclRoot, err := store.Root() require.NoError(t, err) diff --git a/node/storage/spacestorage.go b/node/storage/spacestorage.go index eed05609..018c6b04 100644 --- a/node/storage/spacestorage.go +++ b/node/storage/spacestorage.go @@ -5,7 +5,7 @@ import ( "github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" spacestorage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" - storage2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage" "go.uber.org/zap" "path" "sync" @@ -22,7 +22,7 @@ type spaceStorage struct { spaceId string objDb *pogreb.DB keys spaceKeys - aclStorage storage2.ListStorage + aclStorage storage.ListStorage header *spacesyncproto.RawSpaceHeaderWithId mx sync.Mutex } @@ -129,15 +129,15 @@ func createSpaceStorage(rootPath string, payload spacestorage.SpaceStorageCreate return } -func (s *spaceStorage) ID() string { +func (s *spaceStorage) Id() string { return s.spaceId } -func (s *spaceStorage) TreeStorage(id string) (storage2.TreeStorage, error) { +func (s *spaceStorage) TreeStorage(id string) (storage.TreeStorage, error) { return newTreeStorage(s.objDb, id) } -func (s *spaceStorage) CreateTreeStorage(payload storage2.TreeStorageCreatePayload) (ts storage2.TreeStorage, err error) { +func (s *spaceStorage) CreateTreeStorage(payload storage.TreeStorageCreatePayload) (ts storage.TreeStorage, err error) { // we have mutex here, so we prevent overwriting the heads of a tree on concurrent creation s.mx.Lock() defer s.mx.Unlock() @@ -145,7 +145,7 @@ func (s *spaceStorage) CreateTreeStorage(payload storage2.TreeStorageCreatePaylo return createTreeStorage(s.objDb, payload) } -func (s *spaceStorage) ACLStorage() (storage2.ListStorage, error) { +func (s *spaceStorage) ACLStorage() (storage.ListStorage, error) { return s.aclStorage, nil } diff --git a/node/storage/treestorage.go b/node/storage/treestorage.go index 9b92379d..77234d2f 100644 --- a/node/storage/treestorage.go +++ b/node/storage/treestorage.go @@ -3,7 +3,7 @@ package storage import ( "context" "github.com/akrylysov/pogreb" - storage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto" ) @@ -86,7 +86,7 @@ func createTreeStorage(db *pogreb.DB, payload storage.TreeStorageCreatePayload) return } -func (t *treeStorage) ID() string { +func (t *treeStorage) Id() string { return t.id } diff --git a/node/storage/treestorage_test.go b/node/storage/treestorage_test.go index df83c118..00cce688 100644 --- a/node/storage/treestorage_test.go +++ b/node/storage/treestorage_test.go @@ -43,7 +43,7 @@ func (fx *fixture) stop(t *testing.T) { } func testTreePayload(t *testing.T, store storage.TreeStorage, payload storage.TreeStorageCreatePayload) { - require.Equal(t, payload.RootRawChange.Id, store.ID()) + require.Equal(t, payload.RootRawChange.Id, store.Id()) root, err := store.Root() require.NoError(t, err)