diff --git a/admin/client.go b/admin/client.go index d8616f94e..493e0600e 100644 --- a/admin/client.go +++ b/admin/client.go @@ -348,7 +348,7 @@ func (c *Client) ListChangeSummaries( } var summaries []*types.ChangeSummary for _, c := range changes { - if err := newDoc.ApplyChanges(c); err != nil { + if _, err := newDoc.ApplyChanges(c); err != nil { return nil, err } diff --git a/api/converter/converter_test.go b/api/converter/converter_test.go index c247913a0..c92b047bc 100644 --- a/api/converter/converter_test.go +++ b/api/converter/converter_test.go @@ -24,11 +24,12 @@ import ( "github.com/stretchr/testify/assert" "github.com/yorkie-team/yorkie/api/converter" - "github.com/yorkie-team/yorkie/api/types" api "github.com/yorkie-team/yorkie/api/yorkie/v1" "github.com/yorkie-team/yorkie/pkg/document" "github.com/yorkie-team/yorkie/pkg/document/crdt" + "github.com/yorkie-team/yorkie/pkg/document/innerpresence" "github.com/yorkie-team/yorkie/pkg/document/json" + "github.com/yorkie-team/yorkie/pkg/document/presence" "github.com/yorkie-team/yorkie/pkg/document/time" "github.com/yorkie-team/yorkie/test/helper" ) @@ -41,14 +42,14 @@ func TestConverter(t *testing.T) { doc := document.New("d1") - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewText("k1").Edit(0, 0, "A") return nil }) assert.NoError(t, err) assert.Equal(t, `{"k1":[{"val":"A"}]}`, doc.Marshal()) - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewText("k1").Edit(0, 0, "B") return nil }) @@ -63,10 +64,10 @@ func TestConverter(t *testing.T) { assert.Equal(t, `{"k1":[{"val":"B"}]}`, obj.Marshal()) }) - t.Run("snapshot test", func(t *testing.T) { + t.Run("root snapshot test", func(t *testing.T) { doc := document.New("d1") - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { // an object and primitive types root.SetNewObject("k1"). SetNull("k1.0"). @@ -138,7 +139,7 @@ func TestConverter(t *testing.T) { t.Run("change pack test", func(t *testing.T) { d1 := document.New("d1") - err := d1.Update(func(root *json.Object) error { + err := d1.Update(func(root *json.Object, p *presence.Presence) error { // an object and primitive types root.SetNewObject("k1"). SetBool("k1.1", true). @@ -209,28 +210,6 @@ func TestConverter(t *testing.T) { assert.ErrorIs(t, err, converter.ErrCheckpointRequired) }) - t.Run("client test", func(t *testing.T) { - cli := types.Client{ - ID: time.InitialActorID, - PresenceInfo: types.PresenceInfo{ - Presence: types.Presence{"Name": "ClientName"}, - }, - } - - pbCli := converter.ToClient(cli) - decodedCli, err := converter.FromClient(pbCli) - assert.NoError(t, err) - assert.Equal(t, cli.ID.Bytes(), decodedCli.ID.Bytes()) - assert.Equal(t, cli.PresenceInfo, decodedCli.PresenceInfo) - - pbClients := converter.ToClients([]types.Client{cli}) - - decodedCli, err = converter.FromClient(pbClients[0]) - assert.NoError(t, err) - assert.Equal(t, cli.ID.Bytes(), decodedCli.ID.Bytes()) - assert.Equal(t, cli.PresenceInfo, decodedCli.PresenceInfo) - }) - t.Run("tree converting test", func(t *testing.T) { root := helper.BuildTreeNode(&json.TreeNode{ Type: "r", @@ -264,4 +243,13 @@ func TestConverter(t *testing.T) { assert.Equal(t, tree.ToXML(), clone.ToXML()) }) + + t.Run("empty presence converting test", func(t *testing.T) { + change, err := innerpresence.NewChangeFromJSON(`{"ChangeType":"put","Presence":{}}`) + assert.NoError(t, err) + + pbChange := converter.ToPresenceChange(change) + clone := converter.FromPresenceChange(pbChange) + assert.Equal(t, change, clone) + }) } diff --git a/api/converter/from_bytes.go b/api/converter/from_bytes.go index c82a2e3c8..6f0b6e8fa 100644 --- a/api/converter/from_bytes.go +++ b/api/converter/from_bytes.go @@ -24,9 +24,30 @@ import ( api "github.com/yorkie-team/yorkie/api/yorkie/v1" "github.com/yorkie-team/yorkie/pkg/document/crdt" + "github.com/yorkie-team/yorkie/pkg/document/innerpresence" "github.com/yorkie-team/yorkie/pkg/document/time" ) +// BytesToSnapshot creates a Snapshot from the given byte array. +func BytesToSnapshot(snapshot []byte) (*crdt.Object, *innerpresence.Map, error) { + if snapshot == nil { + return crdt.NewObject(crdt.NewElementRHT(), time.InitialTicket), innerpresence.NewMap(), nil + } + + pbSnapshot := &api.Snapshot{} + if err := proto.Unmarshal(snapshot, pbSnapshot); err != nil { + return nil, nil, fmt.Errorf("unmarshal snapshot: %w", err) + } + + obj, err := fromJSONElement(pbSnapshot.GetRoot()) + if err != nil { + return nil, nil, err + } + + presences := fromPresences(pbSnapshot.GetPresences()) + return obj.(*crdt.Object), presences, nil +} + // BytesToObject creates an Object from the given byte array. func BytesToObject(snapshot []byte) (*crdt.Object, error) { if snapshot == nil { diff --git a/api/converter/from_pb.go b/api/converter/from_pb.go index deee8b5f4..7295103be 100644 --- a/api/converter/from_pb.go +++ b/api/converter/from_pb.go @@ -25,6 +25,7 @@ import ( api "github.com/yorkie-team/yorkie/api/yorkie/v1" "github.com/yorkie-team/yorkie/pkg/document/change" "github.com/yorkie-team/yorkie/pkg/document/crdt" + "github.com/yorkie-team/yorkie/pkg/document/innerpresence" "github.com/yorkie-team/yorkie/pkg/document/key" "github.com/yorkie-team/yorkie/pkg/document/operations" "github.com/yorkie-team/yorkie/pkg/document/time" @@ -119,27 +120,6 @@ func FromDocumentSummary(pbSummary *api.DocumentSummary) (*types.DocumentSummary }, nil } -// FromClient converts the given Protobuf formats to model format. -func FromClient(pbClient *api.Client) (*types.Client, error) { - id, err := time.ActorIDFromBytes(pbClient.Id) - if err != nil { - return nil, err - } - - return &types.Client{ - ID: id, - PresenceInfo: FromPresenceInfo(pbClient.Presence), - }, nil -} - -// FromPresenceInfo converts the given Protobuf formats to model format. -func FromPresenceInfo(pbPresence *api.Presence) types.PresenceInfo { - return types.PresenceInfo{ - Clock: pbPresence.Clock, - Presence: pbPresence.Data, - } -} - // FromChangePack converts the given Protobuf formats to model format. func FromChangePack(pbPack *api.ChangePack) (*change.Pack, error) { if pbPack == nil { @@ -192,6 +172,7 @@ func FromChanges(pbChanges []*api.Change) ([]*change.Change, error) { changeID, pbChange.Message, ops, + FromPresenceChange(pbChange.PresenceChange), )) } @@ -240,15 +221,13 @@ func FromEventType(pbDocEventType api.DocEventType) (types.DocEventType, error) return types.DocumentsWatchedEvent, nil case api.DocEventType_DOC_EVENT_TYPE_DOCUMENTS_UNWATCHED: return types.DocumentsUnwatchedEvent, nil - case api.DocEventType_DOC_EVENT_TYPE_PRESENCE_CHANGED: - return types.PresenceChangedEvent, nil } return "", fmt.Errorf("%v: %w", pbDocEventType, ErrUnsupportedEventType) } // FromDocEvent converts the given Protobuf formats to model format. func FromDocEvent(docEvent *api.DocEvent) (*sync.DocEvent, error) { - client, err := FromClient(docEvent.Publisher) + client, err := time.ActorIDFromBytes(docEvent.Publisher) if err != nil { return nil, err } @@ -258,32 +237,12 @@ func FromDocEvent(docEvent *api.DocEvent) (*sync.DocEvent, error) { return nil, err } - documentID, err := FromDocumentID(docEvent.DocumentId) - if err != nil { - return nil, err - } - return &sync.DocEvent{ - Type: eventType, - Publisher: *client, - DocumentID: documentID, + Type: eventType, + Publisher: client, }, nil } -// FromClients converts the given Protobuf formats to model format. -func FromClients(pbClients []*api.Client) ([]*types.Client, error) { - var clients []*types.Client - for _, pbClient := range pbClients { - client, err := FromClient(pbClient) - if err != nil { - return nil, err - } - clients = append(clients, client) - } - - return clients, nil -} - // FromOperations converts the given Protobuf formats to model format. func FromOperations(pbOps []*api.Operation) ([]operations.Operation, error) { var ops []operations.Operation @@ -323,6 +282,53 @@ func FromOperations(pbOps []*api.Operation) ([]operations.Operation, error) { return ops, nil } +func fromPresences(pbPresences map[string]*api.Presence) *innerpresence.Map { + presences := innerpresence.NewMap() + for id, pbPresence := range pbPresences { + presences.Store(id, fromPresence(pbPresence)) + } + return presences +} + +func fromPresence(pbPresence *api.Presence) innerpresence.Presence { + if pbPresence == nil { + return nil + } + + data := pbPresence.GetData() + if data == nil { + data = innerpresence.NewPresence() + } + + return data +} + +// FromPresenceChange converts the given Protobuf formats to model format. +func FromPresenceChange(pbPresenceChange *api.PresenceChange) *innerpresence.PresenceChange { + if pbPresenceChange == nil { + return nil + } + + var p innerpresence.PresenceChange + switch pbPresenceChange.Type { + case api.PresenceChange_CHANGE_TYPE_PUT: + p = innerpresence.PresenceChange{ + ChangeType: innerpresence.Put, + Presence: pbPresenceChange.Presence.Data, + } + if p.Presence == nil { + p.Presence = innerpresence.NewPresence() + } + case api.PresenceChange_CHANGE_TYPE_CLEAR: + p = innerpresence.PresenceChange{ + ChangeType: innerpresence.Clear, + Presence: nil, + } + } + + return &p +} + func fromSet(pbSet *api.Operation_Set) (*operations.Set, error) { parentCreatedAt, err := fromTimeTicket(pbSet.ParentCreatedAt) if err != nil { diff --git a/api/converter/to_bytes.go b/api/converter/to_bytes.go index fdd7de5f6..29fbd54b5 100644 --- a/api/converter/to_bytes.go +++ b/api/converter/to_bytes.go @@ -24,9 +24,30 @@ import ( api "github.com/yorkie-team/yorkie/api/yorkie/v1" "github.com/yorkie-team/yorkie/pkg/document/crdt" + "github.com/yorkie-team/yorkie/pkg/document/innerpresence" "github.com/yorkie-team/yorkie/pkg/index" ) +// SnapshotToBytes converts the given document to byte array. +func SnapshotToBytes(obj *crdt.Object, presences *innerpresence.Map) ([]byte, error) { + pbElem, err := toJSONElement(obj) + if err != nil { + return nil, err + } + + pbPresences := ToPresences(presences) + + bytes, err := proto.Marshal(&api.Snapshot{ + Root: pbElem, + Presences: pbPresences, + }) + if err != nil { + return nil, fmt.Errorf("marshal Snapshot to bytes: %w", err) + } + + return bytes, nil +} + // ObjectToBytes converts the given object to byte array. func ObjectToBytes(obj *crdt.Object) ([]byte, error) { pbElem, err := toJSONElement(obj) diff --git a/api/converter/to_pb.go b/api/converter/to_pb.go index be40e3273..0867437e5 100644 --- a/api/converter/to_pb.go +++ b/api/converter/to_pb.go @@ -26,6 +26,7 @@ import ( api "github.com/yorkie-team/yorkie/api/yorkie/v1" "github.com/yorkie-team/yorkie/pkg/document/change" "github.com/yorkie-team/yorkie/pkg/document/crdt" + "github.com/yorkie-team/yorkie/pkg/document/innerpresence" "github.com/yorkie-team/yorkie/pkg/document/operations" "github.com/yorkie-team/yorkie/pkg/document/time" "github.com/yorkie-team/yorkie/server/backend/sync" @@ -121,19 +122,46 @@ func ToDocumentSummary(summary *types.DocumentSummary) (*api.DocumentSummary, er }, nil } -// ToClient converts the given model to Protobuf format. -func ToClient(client types.Client) *api.Client { - return &api.Client{ - Id: client.ID.Bytes(), - Presence: ToPresenceInfo(client.PresenceInfo), - } +// ToPresences converts the given model to Protobuf format. +func ToPresences(presences *innerpresence.Map) map[string]*api.Presence { + pbPresences := make(map[string]*api.Presence) + presences.Range(func(k string, v innerpresence.Presence) bool { + pbPresences[k] = ToPresence(v) + return true + }) + return pbPresences } -// ToPresenceInfo converts the given model to Protobuf format. -func ToPresenceInfo(info types.PresenceInfo) *api.Presence { +// ToPresence converts the given model to Protobuf format. +func ToPresence(p innerpresence.Presence) *api.Presence { + if p == nil { + return nil + } + return &api.Presence{ - Clock: info.Clock, - Data: info.Presence, + Data: p, + } +} + +// ToPresenceChange converts the given model to Protobuf format. +func ToPresenceChange(p *innerpresence.PresenceChange) *api.PresenceChange { + if p == nil { + return nil + } + + switch p.ChangeType { + case innerpresence.Put: + return &api.PresenceChange{ + Type: api.PresenceChange_CHANGE_TYPE_PUT, + Presence: &api.Presence{Data: p.Presence}, + } + case innerpresence.Clear: + return &api.PresenceChange{ + Type: api.PresenceChange_CHANGE_TYPE_CLEAR, + } + } + return &api.PresenceChange{ + Type: api.PresenceChange_CHANGE_TYPE_UNSPECIFIED, } } @@ -172,15 +200,6 @@ func ToChangeID(id change.ID) *api.ChangeID { } } -// ToClients converts the given model to Protobuf format. -func ToClients(clients []types.Client) []*api.Client { - var pbClients []*api.Client - for _, client := range clients { - pbClients = append(pbClients, ToClient(client)) - } - return pbClients -} - // ToDocEventType converts the given model format to Protobuf format. func ToDocEventType(eventType types.DocEventType) (api.DocEventType, error) { switch eventType { @@ -190,8 +209,6 @@ func ToDocEventType(eventType types.DocEventType) (api.DocEventType, error) { return api.DocEventType_DOC_EVENT_TYPE_DOCUMENTS_WATCHED, nil case types.DocumentsUnwatchedEvent: return api.DocEventType_DOC_EVENT_TYPE_DOCUMENTS_UNWATCHED, nil - case types.PresenceChangedEvent: - return api.DocEventType_DOC_EVENT_TYPE_PRESENCE_CHANGED, nil default: return 0, fmt.Errorf("%s: %w", eventType, ErrUnsupportedEventType) } @@ -205,9 +222,8 @@ func ToDocEvent(docEvent sync.DocEvent) (*api.DocEvent, error) { } return &api.DocEvent{ - Type: eventType, - Publisher: ToClient(docEvent.Publisher), - DocumentId: docEvent.DocumentID.String(), + Type: eventType, + Publisher: docEvent.Publisher.Bytes(), }, nil } @@ -275,9 +291,10 @@ func ToChanges(changes []*change.Change) ([]*api.Change, error) { } pbChanges = append(pbChanges, &api.Change{ - Id: ToChangeID(c.ID()), - Message: c.Message(), - Operations: pbOperations, + Id: ToChangeID(c.ID()), + Message: c.Message(), + Operations: pbOperations, + PresenceChange: ToPresenceChange(c.PresenceChange()), }) } diff --git a/api/types/client.go b/api/types/client.go deleted file mode 100644 index ff2a0fab8..000000000 --- a/api/types/client.go +++ /dev/null @@ -1,53 +0,0 @@ -package types - -import ( - "encoding/json" - "fmt" - - "github.com/yorkie-team/yorkie/pkg/document/time" -) - -// Client represents the Client that communicates with the Server. -type Client struct { - ID *time.ActorID - PresenceInfo PresenceInfo -} - -// NewClient creates a new Client from the given JSON. -func NewClient(encoded []byte) (*Client, error) { - cli := &Client{} - err := json.Unmarshal(encoded, cli) - if err != nil { - return nil, fmt.Errorf("unmarshal client: %w", err) - } - return cli, nil -} - -// Marshal serializes the Client to JSON. -func (c *Client) Marshal() (string, error) { - encoded, err := json.Marshal(c) - if err != nil { - return "", fmt.Errorf("marshal client: %w", err) - } - - return string(encoded), nil -} - -// Presence represents custom presence that can be defined in the client. -type Presence map[string]string - -// PresenceInfo is a presence information with logical clock. -type PresenceInfo struct { - Clock int32 - Presence Presence -} - -// Update updates the given presence information with the given clock. -func (i *PresenceInfo) Update(info PresenceInfo) bool { - if info.Clock > i.Clock { - i.Clock = info.Clock - i.Presence = info.Presence - return true - } - return false -} diff --git a/api/types/event.go b/api/types/event.go index 7472e6816..d04de35bc 100644 --- a/api/types/event.go +++ b/api/types/event.go @@ -15,7 +15,4 @@ const ( // DocumentsUnwatchedEvent is an event that occurs when documents are // unwatched by other clients. DocumentsUnwatchedEvent DocEventType = "documents-unwatched" - - // PresenceChangedEvent is an event indicating that presence is changed. - PresenceChangedEvent DocEventType = "presence-changed" ) diff --git a/api/yorkie/v1/resources.pb.go b/api/yorkie/v1/resources.pb.go index b33c3167a..3e8c98cc3 100644 --- a/api/yorkie/v1/resources.pb.go +++ b/api/yorkie/v1/resources.pb.go @@ -90,21 +90,18 @@ const ( DocEventType_DOC_EVENT_TYPE_DOCUMENTS_CHANGED DocEventType = 0 DocEventType_DOC_EVENT_TYPE_DOCUMENTS_WATCHED DocEventType = 1 DocEventType_DOC_EVENT_TYPE_DOCUMENTS_UNWATCHED DocEventType = 2 - DocEventType_DOC_EVENT_TYPE_PRESENCE_CHANGED DocEventType = 3 ) var DocEventType_name = map[int32]string{ 0: "DOC_EVENT_TYPE_DOCUMENTS_CHANGED", 1: "DOC_EVENT_TYPE_DOCUMENTS_WATCHED", 2: "DOC_EVENT_TYPE_DOCUMENTS_UNWATCHED", - 3: "DOC_EVENT_TYPE_PRESENCE_CHANGED", } var DocEventType_value = map[string]int32{ "DOC_EVENT_TYPE_DOCUMENTS_CHANGED": 0, "DOC_EVENT_TYPE_DOCUMENTS_WATCHED": 1, "DOC_EVENT_TYPE_DOCUMENTS_UNWATCHED": 2, - "DOC_EVENT_TYPE_PRESENCE_CHANGED": 3, } func (x DocEventType) String() string { @@ -115,6 +112,95 @@ func (DocEventType) EnumDescriptor() ([]byte, []int) { return fileDescriptor_36361b2f5d0f0896, []int{1} } +type PresenceChange_ChangeType int32 + +const ( + PresenceChange_CHANGE_TYPE_UNSPECIFIED PresenceChange_ChangeType = 0 + PresenceChange_CHANGE_TYPE_PUT PresenceChange_ChangeType = 1 + PresenceChange_CHANGE_TYPE_DELETE PresenceChange_ChangeType = 2 + PresenceChange_CHANGE_TYPE_CLEAR PresenceChange_ChangeType = 3 +) + +var PresenceChange_ChangeType_name = map[int32]string{ + 0: "CHANGE_TYPE_UNSPECIFIED", + 1: "CHANGE_TYPE_PUT", + 2: "CHANGE_TYPE_DELETE", + 3: "CHANGE_TYPE_CLEAR", +} + +var PresenceChange_ChangeType_value = map[string]int32{ + "CHANGE_TYPE_UNSPECIFIED": 0, + "CHANGE_TYPE_PUT": 1, + "CHANGE_TYPE_DELETE": 2, + "CHANGE_TYPE_CLEAR": 3, +} + +func (x PresenceChange_ChangeType) String() string { + return proto.EnumName(PresenceChange_ChangeType_name, int32(x)) +} + +func (PresenceChange_ChangeType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_36361b2f5d0f0896, []int{19, 0} +} + +// /////////////////////////////////////// +// Messages for Snapshot // +// /////////////////////////////////////// +type Snapshot struct { + Root *JSONElement `protobuf:"bytes,1,opt,name=root,proto3" json:"root,omitempty"` + Presences map[string]*Presence `protobuf:"bytes,2,rep,name=presences,proto3" json:"presences,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Snapshot) Reset() { *m = Snapshot{} } +func (m *Snapshot) String() string { return proto.CompactTextString(m) } +func (*Snapshot) ProtoMessage() {} +func (*Snapshot) Descriptor() ([]byte, []int) { + return fileDescriptor_36361b2f5d0f0896, []int{0} +} +func (m *Snapshot) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Snapshot) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Snapshot.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 *Snapshot) XXX_Merge(src proto.Message) { + xxx_messageInfo_Snapshot.Merge(m, src) +} +func (m *Snapshot) XXX_Size() int { + return m.Size() +} +func (m *Snapshot) XXX_DiscardUnknown() { + xxx_messageInfo_Snapshot.DiscardUnknown(m) +} + +var xxx_messageInfo_Snapshot proto.InternalMessageInfo + +func (m *Snapshot) GetRoot() *JSONElement { + if m != nil { + return m.Root + } + return nil +} + +func (m *Snapshot) GetPresences() map[string]*Presence { + if m != nil { + return m.Presences + } + return nil +} + // ChangePack is a message that contains all changes that occurred in a document. // It is used to synchronize changes between clients and servers. type ChangePack struct { @@ -133,7 +219,7 @@ func (m *ChangePack) Reset() { *m = ChangePack{} } func (m *ChangePack) String() string { return proto.CompactTextString(m) } func (*ChangePack) ProtoMessage() {} func (*ChangePack) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{0} + return fileDescriptor_36361b2f5d0f0896, []int{1} } func (m *ChangePack) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -205,19 +291,20 @@ func (m *ChangePack) GetIsRemoved() bool { } type Change struct { - Id *ChangeID `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` - Operations []*Operation `protobuf:"bytes,3,rep,name=operations,proto3" json:"operations,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Id *ChangeID `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` + Operations []*Operation `protobuf:"bytes,3,rep,name=operations,proto3" json:"operations,omitempty"` + PresenceChange *PresenceChange `protobuf:"bytes,4,opt,name=presence_change,json=presenceChange,proto3" json:"presence_change,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Change) Reset() { *m = Change{} } func (m *Change) String() string { return proto.CompactTextString(m) } func (*Change) ProtoMessage() {} func (*Change) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{1} + return fileDescriptor_36361b2f5d0f0896, []int{2} } func (m *Change) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -267,6 +354,13 @@ func (m *Change) GetOperations() []*Operation { return nil } +func (m *Change) GetPresenceChange() *PresenceChange { + if m != nil { + return m.PresenceChange + } + return nil +} + type ChangeID struct { ClientSeq uint32 `protobuf:"varint,1,opt,name=client_seq,json=clientSeq,proto3" json:"client_seq,omitempty"` ServerSeq int64 `protobuf:"varint,2,opt,name=server_seq,json=serverSeq,proto3" json:"server_seq,omitempty"` @@ -281,7 +375,7 @@ func (m *ChangeID) Reset() { *m = ChangeID{} } func (m *ChangeID) String() string { return proto.CompactTextString(m) } func (*ChangeID) ProtoMessage() {} func (*ChangeID) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{2} + return fileDescriptor_36361b2f5d0f0896, []int{3} } func (m *ChangeID) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -361,7 +455,7 @@ func (m *Operation) Reset() { *m = Operation{} } func (m *Operation) String() string { return proto.CompactTextString(m) } func (*Operation) ProtoMessage() {} func (*Operation) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{3} + return fileDescriptor_36361b2f5d0f0896, []int{4} } func (m *Operation) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -545,7 +639,7 @@ func (m *Operation_Set) Reset() { *m = Operation_Set{} } func (m *Operation_Set) String() string { return proto.CompactTextString(m) } func (*Operation_Set) ProtoMessage() {} func (*Operation_Set) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{3, 0} + return fileDescriptor_36361b2f5d0f0896, []int{4, 0} } func (m *Operation_Set) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -616,7 +710,7 @@ func (m *Operation_Add) Reset() { *m = Operation_Add{} } func (m *Operation_Add) String() string { return proto.CompactTextString(m) } func (*Operation_Add) ProtoMessage() {} func (*Operation_Add) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{3, 1} + return fileDescriptor_36361b2f5d0f0896, []int{4, 1} } func (m *Operation_Add) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -687,7 +781,7 @@ func (m *Operation_Move) Reset() { *m = Operation_Move{} } func (m *Operation_Move) String() string { return proto.CompactTextString(m) } func (*Operation_Move) ProtoMessage() {} func (*Operation_Move) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{3, 2} + return fileDescriptor_36361b2f5d0f0896, []int{4, 2} } func (m *Operation_Move) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -757,7 +851,7 @@ func (m *Operation_Remove) Reset() { *m = Operation_Remove{} } func (m *Operation_Remove) String() string { return proto.CompactTextString(m) } func (*Operation_Remove) ProtoMessage() {} func (*Operation_Remove) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{3, 3} + return fileDescriptor_36361b2f5d0f0896, []int{4, 3} } func (m *Operation_Remove) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -824,7 +918,7 @@ func (m *Operation_Edit) Reset() { *m = Operation_Edit{} } func (m *Operation_Edit) String() string { return proto.CompactTextString(m) } func (*Operation_Edit) ProtoMessage() {} func (*Operation_Edit) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{3, 4} + return fileDescriptor_36361b2f5d0f0896, []int{4, 4} } func (m *Operation_Edit) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -916,7 +1010,7 @@ func (m *Operation_Select) Reset() { *m = Operation_Select{} } func (m *Operation_Select) String() string { return proto.CompactTextString(m) } func (*Operation_Select) ProtoMessage() {} func (*Operation_Select) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{3, 5} + return fileDescriptor_36361b2f5d0f0896, []int{4, 5} } func (m *Operation_Select) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -988,7 +1082,7 @@ func (m *Operation_Style) Reset() { *m = Operation_Style{} } func (m *Operation_Style) String() string { return proto.CompactTextString(m) } func (*Operation_Style) ProtoMessage() {} func (*Operation_Style) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{3, 6} + return fileDescriptor_36361b2f5d0f0896, []int{4, 6} } func (m *Operation_Style) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1065,7 +1159,7 @@ func (m *Operation_Increase) Reset() { *m = Operation_Increase{} } func (m *Operation_Increase) String() string { return proto.CompactTextString(m) } func (*Operation_Increase) ProtoMessage() {} func (*Operation_Increase) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{3, 7} + return fileDescriptor_36361b2f5d0f0896, []int{4, 7} } func (m *Operation_Increase) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1130,7 +1224,7 @@ func (m *Operation_TreeEdit) Reset() { *m = Operation_TreeEdit{} } func (m *Operation_TreeEdit) String() string { return proto.CompactTextString(m) } func (*Operation_TreeEdit) ProtoMessage() {} func (*Operation_TreeEdit) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{3, 8} + return fileDescriptor_36361b2f5d0f0896, []int{4, 8} } func (m *Operation_TreeEdit) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1209,7 +1303,7 @@ func (m *Operation_TreeStyle) Reset() { *m = Operation_TreeStyle{} } func (m *Operation_TreeStyle) String() string { return proto.CompactTextString(m) } func (*Operation_TreeStyle) ProtoMessage() {} func (*Operation_TreeStyle) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{3, 9} + return fileDescriptor_36361b2f5d0f0896, []int{4, 9} } func (m *Operation_TreeStyle) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1288,7 +1382,7 @@ func (m *JSONElementSimple) Reset() { *m = JSONElementSimple{} } func (m *JSONElementSimple) String() string { return proto.CompactTextString(m) } func (*JSONElementSimple) ProtoMessage() {} func (*JSONElementSimple) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{4} + return fileDescriptor_36361b2f5d0f0896, []int{5} } func (m *JSONElementSimple) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1371,7 +1465,7 @@ func (m *JSONElement) Reset() { *m = JSONElement{} } func (m *JSONElement) String() string { return proto.CompactTextString(m) } func (*JSONElement) ProtoMessage() {} func (*JSONElement) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{5} + return fileDescriptor_36361b2f5d0f0896, []int{6} } func (m *JSONElement) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1507,7 +1601,7 @@ func (m *JSONElement_JSONObject) Reset() { *m = JSONElement_JSONObject{} func (m *JSONElement_JSONObject) String() string { return proto.CompactTextString(m) } func (*JSONElement_JSONObject) ProtoMessage() {} func (*JSONElement_JSONObject) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{5, 0} + return fileDescriptor_36361b2f5d0f0896, []int{6, 0} } func (m *JSONElement_JSONObject) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1578,7 +1672,7 @@ func (m *JSONElement_JSONArray) Reset() { *m = JSONElement_JSONArray{} } func (m *JSONElement_JSONArray) String() string { return proto.CompactTextString(m) } func (*JSONElement_JSONArray) ProtoMessage() {} func (*JSONElement_JSONArray) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{5, 1} + return fileDescriptor_36361b2f5d0f0896, []int{6, 1} } func (m *JSONElement_JSONArray) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1650,7 +1744,7 @@ func (m *JSONElement_Primitive) Reset() { *m = JSONElement_Primitive{} } func (m *JSONElement_Primitive) String() string { return proto.CompactTextString(m) } func (*JSONElement_Primitive) ProtoMessage() {} func (*JSONElement_Primitive) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{5, 2} + return fileDescriptor_36361b2f5d0f0896, []int{6, 2} } func (m *JSONElement_Primitive) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1728,7 +1822,7 @@ func (m *JSONElement_Text) Reset() { *m = JSONElement_Text{} } func (m *JSONElement_Text) String() string { return proto.CompactTextString(m) } func (*JSONElement_Text) ProtoMessage() {} func (*JSONElement_Text) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{5, 3} + return fileDescriptor_36361b2f5d0f0896, []int{6, 3} } func (m *JSONElement_Text) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1800,7 +1894,7 @@ func (m *JSONElement_Counter) Reset() { *m = JSONElement_Counter{} } func (m *JSONElement_Counter) String() string { return proto.CompactTextString(m) } func (*JSONElement_Counter) ProtoMessage() {} func (*JSONElement_Counter) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{5, 4} + return fileDescriptor_36361b2f5d0f0896, []int{6, 4} } func (m *JSONElement_Counter) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1878,7 +1972,7 @@ func (m *JSONElement_Tree) Reset() { *m = JSONElement_Tree{} } func (m *JSONElement_Tree) String() string { return proto.CompactTextString(m) } func (*JSONElement_Tree) ProtoMessage() {} func (*JSONElement_Tree) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{5, 5} + return fileDescriptor_36361b2f5d0f0896, []int{6, 5} } func (m *JSONElement_Tree) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1947,7 +2041,7 @@ func (m *RHTNode) Reset() { *m = RHTNode{} } func (m *RHTNode) String() string { return proto.CompactTextString(m) } func (*RHTNode) ProtoMessage() {} func (*RHTNode) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{6} + return fileDescriptor_36361b2f5d0f0896, []int{7} } func (m *RHTNode) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2002,7 +2096,7 @@ func (m *RGANode) Reset() { *m = RGANode{} } func (m *RGANode) String() string { return proto.CompactTextString(m) } func (*RGANode) ProtoMessage() {} func (*RGANode) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{7} + return fileDescriptor_36361b2f5d0f0896, []int{8} } func (m *RGANode) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2057,7 +2151,7 @@ func (m *NodeAttr) Reset() { *m = NodeAttr{} } func (m *NodeAttr) String() string { return proto.CompactTextString(m) } func (*NodeAttr) ProtoMessage() {} func (*NodeAttr) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{8} + return fileDescriptor_36361b2f5d0f0896, []int{9} } func (m *NodeAttr) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2115,7 +2209,7 @@ func (m *TextNode) Reset() { *m = TextNode{} } func (m *TextNode) String() string { return proto.CompactTextString(m) } func (*TextNode) ProtoMessage() {} func (*TextNode) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{9} + return fileDescriptor_36361b2f5d0f0896, []int{10} } func (m *TextNode) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2191,7 +2285,7 @@ func (m *TextNodeID) Reset() { *m = TextNodeID{} } func (m *TextNodeID) String() string { return proto.CompactTextString(m) } func (*TextNodeID) ProtoMessage() {} func (*TextNodeID) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{10} + return fileDescriptor_36361b2f5d0f0896, []int{11} } func (m *TextNodeID) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2251,7 +2345,7 @@ func (m *TreeNode) Reset() { *m = TreeNode{} } func (m *TreeNode) String() string { return proto.CompactTextString(m) } func (*TreeNode) ProtoMessage() {} func (*TreeNode) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{11} + return fileDescriptor_36361b2f5d0f0896, []int{12} } func (m *TreeNode) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2340,7 +2434,7 @@ func (m *TreeNodes) Reset() { *m = TreeNodes{} } func (m *TreeNodes) String() string { return proto.CompactTextString(m) } func (*TreeNodes) ProtoMessage() {} func (*TreeNodes) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{12} + return fileDescriptor_36361b2f5d0f0896, []int{13} } func (m *TreeNodes) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2388,7 +2482,7 @@ func (m *TreePos) Reset() { *m = TreePos{} } func (m *TreePos) String() string { return proto.CompactTextString(m) } func (*TreePos) ProtoMessage() {} func (*TreePos) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{13} + return fileDescriptor_36361b2f5d0f0896, []int{14} } func (m *TreePos) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2444,7 +2538,7 @@ func (m *User) Reset() { *m = User{} } func (m *User) String() string { return proto.CompactTextString(m) } func (*User) ProtoMessage() {} func (*User) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{14} + return fileDescriptor_36361b2f5d0f0896, []int{15} } func (m *User) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2513,7 +2607,7 @@ func (m *Project) Reset() { *m = Project{} } func (m *Project) String() string { return proto.CompactTextString(m) } func (*Project) ProtoMessage() {} func (*Project) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{15} + return fileDescriptor_36361b2f5d0f0896, []int{16} } func (m *Project) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2619,7 +2713,7 @@ func (m *UpdatableProjectFields) Reset() { *m = UpdatableProjectFields{} func (m *UpdatableProjectFields) String() string { return proto.CompactTextString(m) } func (*UpdatableProjectFields) ProtoMessage() {} func (*UpdatableProjectFields) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{16} + return fileDescriptor_36361b2f5d0f0896, []int{17} } func (m *UpdatableProjectFields) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2691,7 +2785,7 @@ func (m *UpdatableProjectFields_AuthWebhookMethods) String() string { } func (*UpdatableProjectFields_AuthWebhookMethods) ProtoMessage() {} func (*UpdatableProjectFields_AuthWebhookMethods) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{16, 0} + return fileDescriptor_36361b2f5d0f0896, []int{17, 0} } func (m *UpdatableProjectFields_AuthWebhookMethods) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2743,7 +2837,7 @@ func (m *DocumentSummary) Reset() { *m = DocumentSummary{} } func (m *DocumentSummary) String() string { return proto.CompactTextString(m) } func (*DocumentSummary) ProtoMessage() {} func (*DocumentSummary) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{17} + return fileDescriptor_36361b2f5d0f0896, []int{18} } func (m *DocumentSummary) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2814,26 +2908,26 @@ func (m *DocumentSummary) GetUpdatedAt() *types.Timestamp { return nil } -type Presence struct { - Clock int32 `protobuf:"varint,1,opt,name=clock,proto3" json:"clock,omitempty"` - Data map[string]string `protobuf:"bytes,2,rep,name=data,proto3" json:"data,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` +type PresenceChange struct { + Type PresenceChange_ChangeType `protobuf:"varint,1,opt,name=type,proto3,enum=yorkie.v1.PresenceChange_ChangeType" json:"type,omitempty"` + Presence *Presence `protobuf:"bytes,2,opt,name=presence,proto3" json:"presence,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *Presence) Reset() { *m = Presence{} } -func (m *Presence) String() string { return proto.CompactTextString(m) } -func (*Presence) ProtoMessage() {} -func (*Presence) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{18} +func (m *PresenceChange) Reset() { *m = PresenceChange{} } +func (m *PresenceChange) String() string { return proto.CompactTextString(m) } +func (*PresenceChange) ProtoMessage() {} +func (*PresenceChange) Descriptor() ([]byte, []int) { + return fileDescriptor_36361b2f5d0f0896, []int{19} } -func (m *Presence) XXX_Unmarshal(b []byte) error { +func (m *PresenceChange) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *Presence) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *PresenceChange) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_Presence.Marshal(b, m, deterministic) + return xxx_messageInfo_PresenceChange.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -2843,52 +2937,51 @@ func (m *Presence) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return b[:n], nil } } -func (m *Presence) XXX_Merge(src proto.Message) { - xxx_messageInfo_Presence.Merge(m, src) +func (m *PresenceChange) XXX_Merge(src proto.Message) { + xxx_messageInfo_PresenceChange.Merge(m, src) } -func (m *Presence) XXX_Size() int { +func (m *PresenceChange) XXX_Size() int { return m.Size() } -func (m *Presence) XXX_DiscardUnknown() { - xxx_messageInfo_Presence.DiscardUnknown(m) +func (m *PresenceChange) XXX_DiscardUnknown() { + xxx_messageInfo_PresenceChange.DiscardUnknown(m) } -var xxx_messageInfo_Presence proto.InternalMessageInfo +var xxx_messageInfo_PresenceChange proto.InternalMessageInfo -func (m *Presence) GetClock() int32 { +func (m *PresenceChange) GetType() PresenceChange_ChangeType { if m != nil { - return m.Clock + return m.Type } - return 0 + return PresenceChange_CHANGE_TYPE_UNSPECIFIED } -func (m *Presence) GetData() map[string]string { +func (m *PresenceChange) GetPresence() *Presence { if m != nil { - return m.Data + return m.Presence } return nil } -type Client struct { - Id []byte `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Presence *Presence `protobuf:"bytes,2,opt,name=presence,proto3" json:"presence,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` +type Presence struct { + Data map[string]string `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *Client) Reset() { *m = Client{} } -func (m *Client) String() string { return proto.CompactTextString(m) } -func (*Client) ProtoMessage() {} -func (*Client) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{19} +func (m *Presence) Reset() { *m = Presence{} } +func (m *Presence) String() string { return proto.CompactTextString(m) } +func (*Presence) ProtoMessage() {} +func (*Presence) Descriptor() ([]byte, []int) { + return fileDescriptor_36361b2f5d0f0896, []int{20} } -func (m *Client) XXX_Unmarshal(b []byte) error { +func (m *Presence) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *Client) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *Presence) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_Client.Marshal(b, m, deterministic) + return xxx_messageInfo_Presence.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -2898,28 +2991,21 @@ func (m *Client) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return b[:n], nil } } -func (m *Client) XXX_Merge(src proto.Message) { - xxx_messageInfo_Client.Merge(m, src) +func (m *Presence) XXX_Merge(src proto.Message) { + xxx_messageInfo_Presence.Merge(m, src) } -func (m *Client) XXX_Size() int { +func (m *Presence) XXX_Size() int { return m.Size() } -func (m *Client) XXX_DiscardUnknown() { - xxx_messageInfo_Client.DiscardUnknown(m) +func (m *Presence) XXX_DiscardUnknown() { + xxx_messageInfo_Presence.DiscardUnknown(m) } -var xxx_messageInfo_Client proto.InternalMessageInfo - -func (m *Client) GetId() []byte { - if m != nil { - return m.Id - } - return nil -} +var xxx_messageInfo_Presence proto.InternalMessageInfo -func (m *Client) GetPresence() *Presence { +func (m *Presence) GetData() map[string]string { if m != nil { - return m.Presence + return m.Data } return nil } @@ -2936,7 +3022,7 @@ func (m *Checkpoint) Reset() { *m = Checkpoint{} } func (m *Checkpoint) String() string { return proto.CompactTextString(m) } func (*Checkpoint) ProtoMessage() {} func (*Checkpoint) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{20} + return fileDescriptor_36361b2f5d0f0896, []int{21} } func (m *Checkpoint) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2992,7 +3078,7 @@ func (m *TextNodePos) Reset() { *m = TextNodePos{} } func (m *TextNodePos) String() string { return proto.CompactTextString(m) } func (*TextNodePos) ProtoMessage() {} func (*TextNodePos) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{21} + return fileDescriptor_36361b2f5d0f0896, []int{22} } func (m *TextNodePos) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3055,7 +3141,7 @@ func (m *TimeTicket) Reset() { *m = TimeTicket{} } func (m *TimeTicket) String() string { return proto.CompactTextString(m) } func (*TimeTicket) ProtoMessage() {} func (*TimeTicket) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{22} + return fileDescriptor_36361b2f5d0f0896, []int{23} } func (m *TimeTicket) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3107,8 +3193,7 @@ func (m *TimeTicket) GetActorId() []byte { type DocEvent struct { Type DocEventType `protobuf:"varint,1,opt,name=type,proto3,enum=yorkie.v1.DocEventType" json:"type,omitempty"` - Publisher *Client `protobuf:"bytes,2,opt,name=publisher,proto3" json:"publisher,omitempty"` - DocumentId string `protobuf:"bytes,3,opt,name=document_id,json=documentId,proto3" json:"document_id,omitempty"` + Publisher []byte `protobuf:"bytes,2,opt,name=publisher,proto3" json:"publisher,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -3118,7 +3203,7 @@ func (m *DocEvent) Reset() { *m = DocEvent{} } func (m *DocEvent) String() string { return proto.CompactTextString(m) } func (*DocEvent) ProtoMessage() {} func (*DocEvent) Descriptor() ([]byte, []int) { - return fileDescriptor_36361b2f5d0f0896, []int{23} + return fileDescriptor_36361b2f5d0f0896, []int{24} } func (m *DocEvent) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3154,23 +3239,19 @@ func (m *DocEvent) GetType() DocEventType { return DocEventType_DOC_EVENT_TYPE_DOCUMENTS_CHANGED } -func (m *DocEvent) GetPublisher() *Client { +func (m *DocEvent) GetPublisher() []byte { if m != nil { return m.Publisher } return nil } -func (m *DocEvent) GetDocumentId() string { - if m != nil { - return m.DocumentId - } - return "" -} - func init() { proto.RegisterEnum("yorkie.v1.ValueType", ValueType_name, ValueType_value) proto.RegisterEnum("yorkie.v1.DocEventType", DocEventType_name, DocEventType_value) + proto.RegisterEnum("yorkie.v1.PresenceChange_ChangeType", PresenceChange_ChangeType_name, PresenceChange_ChangeType_value) + proto.RegisterType((*Snapshot)(nil), "yorkie.v1.Snapshot") + proto.RegisterMapType((map[string]*Presence)(nil), "yorkie.v1.Snapshot.PresencesEntry") proto.RegisterType((*ChangePack)(nil), "yorkie.v1.ChangePack") proto.RegisterType((*Change)(nil), "yorkie.v1.Change") proto.RegisterType((*ChangeID)(nil), "yorkie.v1.ChangeID") @@ -3212,9 +3293,9 @@ func init() { proto.RegisterType((*UpdatableProjectFields)(nil), "yorkie.v1.UpdatableProjectFields") proto.RegisterType((*UpdatableProjectFields_AuthWebhookMethods)(nil), "yorkie.v1.UpdatableProjectFields.AuthWebhookMethods") proto.RegisterType((*DocumentSummary)(nil), "yorkie.v1.DocumentSummary") + proto.RegisterType((*PresenceChange)(nil), "yorkie.v1.PresenceChange") proto.RegisterType((*Presence)(nil), "yorkie.v1.Presence") proto.RegisterMapType((map[string]string)(nil), "yorkie.v1.Presence.DataEntry") - proto.RegisterType((*Client)(nil), "yorkie.v1.Client") proto.RegisterType((*Checkpoint)(nil), "yorkie.v1.Checkpoint") proto.RegisterType((*TextNodePos)(nil), "yorkie.v1.TextNodePos") proto.RegisterType((*TimeTicket)(nil), "yorkie.v1.TimeTicket") @@ -3224,161 +3305,231 @@ func init() { func init() { proto.RegisterFile("yorkie/v1/resources.proto", fileDescriptor_36361b2f5d0f0896) } var fileDescriptor_36361b2f5d0f0896 = []byte{ - // 2452 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x5a, 0x4d, 0x6f, 0xdb, 0xc8, - 0xf9, 0x37, 0xa9, 0x57, 0x3e, 0x72, 0x62, 0x65, 0xf2, 0xa6, 0x28, 0x89, 0xe3, 0x28, 0xfb, 0xcf, - 0xdf, 0x49, 0x5a, 0xd9, 0x71, 0x93, 0xbe, 0x24, 0xdd, 0xb6, 0xb2, 0xcc, 0x8d, 0x9d, 0x75, 0x64, - 0x63, 0x24, 0x27, 0xcd, 0xa2, 0x05, 0x41, 0x93, 0x93, 0x88, 0x6b, 0x89, 0xe4, 0x92, 0x94, 0x36, - 0x3a, 0xf4, 0xd2, 0x17, 0xa0, 0x05, 0x7a, 0xe9, 0xad, 0xdf, 0xa0, 0xe8, 0x47, 0xd8, 0x6b, 0x0f, - 0x45, 0x0f, 0x2d, 0x5a, 0xa0, 0x0b, 0xf4, 0xda, 0x4d, 0x0f, 0x45, 0x8f, 0x45, 0xd1, 0xde, 0x0a, - 0x14, 0x33, 0x43, 0x52, 0x14, 0x45, 0x29, 0x8a, 0x6a, 0x2c, 0x12, 0xf4, 0xa6, 0x99, 0xf9, 0x3d, - 0x33, 0xcf, 0xfb, 0x3c, 0x0f, 0x47, 0x70, 0x61, 0x60, 0x39, 0x47, 0x06, 0x59, 0xeb, 0xdf, 0x5e, - 0x73, 0x88, 0x6b, 0xf5, 0x1c, 0x8d, 0xb8, 0x55, 0xdb, 0xb1, 0x3c, 0x0b, 0x49, 0x7c, 0xa9, 0xda, - 0xbf, 0x5d, 0xbe, 0xf2, 0xdc, 0xb2, 0x9e, 0x77, 0xc8, 0x1a, 0x5b, 0x38, 0xec, 0x3d, 0x5b, 0xf3, - 0x8c, 0x2e, 0x71, 0x3d, 0xb5, 0x6b, 0x73, 0x6c, 0x79, 0x39, 0x0e, 0xf8, 0xd8, 0x51, 0x6d, 0x9b, - 0x38, 0xfe, 0x5e, 0x95, 0x9f, 0x89, 0x00, 0xf5, 0xb6, 0x6a, 0x3e, 0x27, 0xfb, 0xaa, 0x76, 0x84, - 0xae, 0xc2, 0xa2, 0x6e, 0x69, 0xbd, 0x2e, 0x31, 0x3d, 0xe5, 0x88, 0x0c, 0x4a, 0xc2, 0x8a, 0xb0, - 0x2a, 0xe1, 0x42, 0x30, 0xf7, 0x3e, 0x19, 0xa0, 0xbb, 0x00, 0x5a, 0x9b, 0x68, 0x47, 0xb6, 0x65, - 0x98, 0x5e, 0x49, 0x5c, 0x11, 0x56, 0x0b, 0x1b, 0x67, 0xab, 0x21, 0x4b, 0xd5, 0x7a, 0xb8, 0x88, - 0x23, 0x40, 0x54, 0x86, 0xbc, 0x6b, 0xaa, 0xb6, 0xdb, 0xb6, 0xbc, 0x52, 0x6a, 0x45, 0x58, 0x5d, - 0xc4, 0xe1, 0x18, 0xdd, 0x82, 0x9c, 0xc6, 0x78, 0x70, 0x4b, 0xe9, 0x95, 0xd4, 0x6a, 0x61, 0xe3, - 0xd4, 0xc8, 0x7e, 0x74, 0x05, 0x07, 0x08, 0x54, 0x83, 0x53, 0x5d, 0xc3, 0x54, 0xdc, 0x81, 0xa9, - 0x11, 0x5d, 0xf1, 0x0c, 0xed, 0x88, 0x78, 0xa5, 0xcc, 0x18, 0x1b, 0x2d, 0xa3, 0x4b, 0x5a, 0x6c, - 0x11, 0x2f, 0x75, 0x0d, 0xb3, 0xc9, 0xe0, 0x7c, 0x02, 0x5d, 0x06, 0x30, 0x5c, 0xc5, 0x21, 0x5d, - 0xab, 0x4f, 0xf4, 0x52, 0x76, 0x45, 0x58, 0xcd, 0x63, 0xc9, 0x70, 0x31, 0x9f, 0xa8, 0x7c, 0x0f, - 0xb2, 0xfc, 0x50, 0x74, 0x0d, 0x44, 0x43, 0x67, 0x4a, 0x28, 0x6c, 0x9c, 0x1e, 0xe3, 0x69, 0x67, - 0x0b, 0x8b, 0x86, 0x8e, 0x4a, 0x90, 0xeb, 0x12, 0xd7, 0x55, 0x9f, 0x13, 0xa6, 0x0d, 0x09, 0x07, - 0x43, 0x74, 0x07, 0xc0, 0xb2, 0x89, 0xa3, 0x7a, 0x86, 0x65, 0xba, 0xa5, 0x14, 0x13, 0xed, 0x4c, - 0x64, 0x9b, 0xbd, 0x60, 0x11, 0x47, 0x70, 0x95, 0x1f, 0x09, 0x90, 0x0f, 0x0e, 0xa0, 0xac, 0x6a, - 0x1d, 0x83, 0x9a, 0xc3, 0x25, 0x1f, 0x31, 0x4e, 0x4e, 0x60, 0x89, 0xcf, 0x34, 0xc9, 0x47, 0xe8, - 0x2a, 0x80, 0x4b, 0x9c, 0x3e, 0x71, 0xd8, 0x32, 0x3d, 0x3e, 0xb5, 0x29, 0xae, 0x0b, 0x58, 0xe2, - 0xb3, 0x14, 0x72, 0x09, 0x72, 0x1d, 0xb5, 0x6b, 0x5b, 0x0e, 0xd7, 0x3b, 0x5f, 0x0f, 0xa6, 0xd0, - 0x05, 0xc8, 0xab, 0x9a, 0x67, 0x39, 0x8a, 0xa1, 0x97, 0xd2, 0xcc, 0x2c, 0x39, 0x36, 0xde, 0xd1, - 0x2b, 0xbf, 0x2d, 0x83, 0x14, 0x72, 0x88, 0xbe, 0x00, 0x29, 0x97, 0x78, 0xbe, 0x2e, 0x4a, 0x49, - 0x42, 0x54, 0x9b, 0xc4, 0xdb, 0x5e, 0xc0, 0x14, 0x46, 0xd1, 0xaa, 0xae, 0xfb, 0xde, 0x91, 0x8c, - 0xae, 0xe9, 0x3a, 0x45, 0xab, 0xba, 0x8e, 0xd6, 0x20, 0x4d, 0x35, 0xcf, 0xf8, 0x2b, 0x6c, 0x5c, - 0x48, 0x84, 0x3f, 0xb2, 0xfa, 0x64, 0x7b, 0x01, 0x33, 0x20, 0xba, 0x0b, 0x59, 0x6e, 0x3d, 0xc6, - 0x73, 0x61, 0xe3, 0x62, 0x22, 0x09, 0xb7, 0xe7, 0xf6, 0x02, 0xf6, 0xc1, 0xf4, 0x1c, 0xa2, 0x1b, - 0x81, 0xb7, 0x24, 0x9f, 0x23, 0xeb, 0x06, 0x95, 0x82, 0x01, 0xe9, 0x39, 0x2e, 0xe9, 0x10, 0xcd, - 0x63, 0x4e, 0x32, 0xe9, 0x9c, 0x26, 0x83, 0xd0, 0x73, 0x38, 0x18, 0x6d, 0x40, 0xc6, 0xf5, 0x06, - 0x1d, 0x52, 0xca, 0x31, 0xaa, 0x72, 0x32, 0x15, 0x45, 0x6c, 0x2f, 0x60, 0x0e, 0x45, 0xf7, 0x21, - 0x6f, 0x98, 0x9a, 0x43, 0x54, 0x97, 0x94, 0xf2, 0x8c, 0xec, 0x72, 0x22, 0xd9, 0x8e, 0x0f, 0xda, - 0x5e, 0xc0, 0x21, 0x01, 0xfa, 0x3a, 0x48, 0x9e, 0x43, 0x88, 0xc2, 0xa4, 0x93, 0xa6, 0x50, 0xb7, - 0x1c, 0x42, 0x7c, 0x09, 0xf3, 0x9e, 0xff, 0x1b, 0x7d, 0x13, 0x80, 0x51, 0x73, 0x9e, 0x81, 0x91, - 0x2f, 0x4f, 0x24, 0x0f, 0xf8, 0x66, 0x27, 0xb2, 0x41, 0xf9, 0xd7, 0x02, 0xa4, 0x9a, 0xc4, 0xa3, - 0xa1, 0x69, 0xab, 0x0e, 0x75, 0x56, 0xca, 0x97, 0x47, 0x74, 0x45, 0x0d, 0x3c, 0x66, 0x52, 0x68, - 0x72, 0x7c, 0x9d, 0xc3, 0x6b, 0x1e, 0x2a, 0x42, 0x8a, 0xe6, 0x1d, 0x1e, 0x48, 0xf4, 0x27, 0x55, - 0x66, 0x5f, 0xed, 0xf4, 0x02, 0xef, 0xb8, 0x14, 0xd9, 0xe8, 0x61, 0x73, 0xaf, 0x21, 0x77, 0x08, - 0xcd, 0x4c, 0x4d, 0xa3, 0x6b, 0x77, 0x08, 0xe6, 0x50, 0xf4, 0x65, 0x28, 0x90, 0x17, 0x44, 0xeb, - 0xf9, 0x2c, 0xa4, 0xa7, 0xb1, 0x00, 0x01, 0xb2, 0xe6, 0x95, 0xff, 0x21, 0x40, 0xaa, 0xa6, 0xeb, - 0xc7, 0x21, 0xc8, 0xbb, 0xb0, 0x64, 0x3b, 0xa4, 0x1f, 0xdd, 0x40, 0x9c, 0xb6, 0xc1, 0x09, 0x8a, - 0x1e, 0x92, 0x7f, 0x9e, 0x52, 0xff, 0x4b, 0x80, 0x34, 0x0d, 0xaf, 0x37, 0x40, 0xec, 0x3b, 0x00, - 0x11, 0xca, 0xd4, 0x34, 0x4a, 0x49, 0x0b, 0xa9, 0xe6, 0x15, 0xfc, 0x13, 0x01, 0xb2, 0x3c, 0x49, - 0x1c, 0x87, 0xe8, 0xa3, 0xbc, 0x8b, 0xf3, 0xf1, 0x9e, 0x9a, 0x95, 0xf7, 0x5f, 0xa5, 0x21, 0xcd, - 0xa2, 0xf7, 0x18, 0x38, 0xbf, 0x09, 0xe9, 0x67, 0x8e, 0xd5, 0xf5, 0x79, 0x3e, 0x17, 0xa5, 0x22, - 0x2f, 0xbc, 0x86, 0xa5, 0x93, 0x7d, 0xcb, 0xc5, 0x0c, 0x83, 0xae, 0x83, 0xe8, 0x59, 0x3e, 0x9b, - 0x93, 0x90, 0xa2, 0x67, 0xa1, 0x36, 0x9c, 0x1f, 0xf2, 0xa3, 0x74, 0x55, 0x5b, 0x39, 0x1c, 0x28, - 0xec, 0x6a, 0xf1, 0xef, 0xf8, 0x8d, 0x89, 0xe9, 0xb7, 0x1a, 0x72, 0xf6, 0x48, 0xb5, 0x37, 0x07, - 0x35, 0x4a, 0x24, 0x9b, 0x9e, 0x33, 0xc0, 0xa7, 0xb5, 0xf1, 0x15, 0x7a, 0xff, 0x6a, 0x96, 0xe9, - 0x11, 0x93, 0x27, 0x76, 0x09, 0x07, 0xc3, 0xb8, 0x6e, 0xb3, 0x33, 0xea, 0x16, 0xed, 0x00, 0xa8, - 0x9e, 0xe7, 0x18, 0x87, 0x3d, 0x8f, 0xb8, 0xa5, 0x1c, 0x63, 0xf7, 0xc6, 0x64, 0x76, 0x6b, 0x21, - 0x96, 0x73, 0x19, 0x21, 0x2e, 0x7f, 0x17, 0x4a, 0x93, 0xa4, 0x09, 0x72, 0x9d, 0x30, 0xcc, 0x75, - 0xb7, 0x82, 0xa8, 0x9f, 0xea, 0x3d, 0x1c, 0x73, 0x4f, 0xfc, 0xaa, 0x50, 0x7e, 0x17, 0x96, 0x62, - 0xa7, 0x27, 0xec, 0x7a, 0x26, 0xba, 0xab, 0x14, 0x25, 0xff, 0x93, 0x00, 0x59, 0x7e, 0x7b, 0xbd, - 0xa9, 0x6e, 0x34, 0x6f, 0x68, 0x7f, 0x26, 0x42, 0x86, 0x5d, 0x4e, 0x6f, 0xaa, 0x60, 0x0f, 0x47, - 0x7c, 0x8c, 0x87, 0xc4, 0xcd, 0xc9, 0x85, 0xc2, 0x34, 0x27, 0x8b, 0x2b, 0x29, 0x33, 0xab, 0x92, - 0xfe, 0x4b, 0xef, 0xf9, 0x44, 0x80, 0x7c, 0x50, 0x8e, 0x1c, 0x87, 0x9a, 0x37, 0x46, 0xbd, 0x7f, - 0x9e, 0x3b, 0x6f, 0xe6, 0xf4, 0xf9, 0x03, 0x11, 0xf2, 0x41, 0x31, 0x74, 0x1c, 0xbc, 0x5f, 0x1f, - 0x71, 0x11, 0x14, 0xa5, 0x72, 0x48, 0xc4, 0x3d, 0x2a, 0x11, 0xf7, 0x48, 0x42, 0x51, 0xd7, 0x58, - 0x87, 0xbc, 0x9f, 0xc1, 0x02, 0xc7, 0x38, 0x13, 0x43, 0x52, 0x47, 0x72, 0x71, 0x88, 0x9a, 0xdb, - 0x01, 0x3e, 0x13, 0x41, 0x0a, 0x6b, 0xba, 0x37, 0x4d, 0x0d, 0x8d, 0x84, 0x08, 0xa9, 0x4e, 0x2f, - 0x4b, 0xdf, 0xc0, 0x28, 0xd9, 0xcc, 0x42, 0xfa, 0xd0, 0xd2, 0x07, 0x95, 0xbf, 0x0b, 0x70, 0x6a, - 0xcc, 0x8d, 0x63, 0x45, 0x83, 0x30, 0x63, 0xd1, 0xb0, 0x0e, 0x79, 0xd6, 0xaa, 0xbe, 0xb2, 0xd0, - 0xc8, 0x31, 0x18, 0x2f, 0x4e, 0xfc, 0x7e, 0xf7, 0xd5, 0x85, 0x95, 0x0f, 0xac, 0x79, 0x68, 0x15, - 0xd2, 0xde, 0xc0, 0xe6, 0x5d, 0xd6, 0xc9, 0x11, 0x2f, 0x7c, 0x4c, 0xe5, 0x6b, 0x0d, 0x6c, 0x82, - 0x19, 0x62, 0x28, 0x7f, 0x86, 0x35, 0x91, 0x7c, 0x50, 0xf9, 0xe5, 0x09, 0x28, 0x44, 0x64, 0x46, - 0x5b, 0x50, 0xf8, 0xd0, 0xb5, 0x4c, 0xc5, 0x3a, 0xfc, 0x90, 0x36, 0x55, 0x5c, 0xdc, 0xab, 0xc9, - 0x71, 0xce, 0x7e, 0xef, 0x31, 0xe0, 0xf6, 0x02, 0x06, 0x4a, 0xc7, 0x47, 0xa8, 0x06, 0x6c, 0xa4, - 0xa8, 0x8e, 0xa3, 0x0e, 0x7c, 0xf9, 0x57, 0xa6, 0x6c, 0x52, 0xa3, 0x38, 0xda, 0xb1, 0x50, 0x2a, - 0x36, 0x40, 0xdf, 0x02, 0xc9, 0x76, 0x8c, 0xae, 0xe1, 0x19, 0x61, 0xdb, 0x39, 0x69, 0x87, 0xfd, - 0x00, 0x47, 0x77, 0x08, 0x89, 0xd0, 0x6d, 0x48, 0x7b, 0xe4, 0x45, 0xe0, 0x46, 0x17, 0x27, 0x10, - 0xd3, 0xac, 0x4f, 0xbb, 0x49, 0x0a, 0x45, 0xf7, 0x68, 0xa1, 0xd2, 0x33, 0x3d, 0xe2, 0xf8, 0xa5, - 0xc8, 0xf2, 0x04, 0xaa, 0x3a, 0x47, 0x6d, 0x2f, 0xe0, 0x80, 0x80, 0x1d, 0xe7, 0x90, 0xa0, 0xa3, - 0x9c, 0x78, 0x9c, 0x43, 0x58, 0x93, 0x4c, 0xa1, 0xe5, 0x4f, 0x05, 0x80, 0xa1, 0x0e, 0xd1, 0x2a, - 0x64, 0x4c, 0x9a, 0x36, 0x4a, 0x02, 0x8b, 0xa4, 0x68, 0xd4, 0xe1, 0xed, 0x16, 0xcd, 0x28, 0x98, - 0x03, 0xe6, 0x2c, 0x64, 0xa3, 0x3e, 0x99, 0x9a, 0xc3, 0x27, 0xd3, 0xb3, 0xf9, 0x64, 0xf9, 0x8f, - 0x02, 0x48, 0xa1, 0x55, 0xa7, 0x4a, 0xf5, 0xa0, 0xf6, 0xf6, 0x48, 0xf5, 0x37, 0x01, 0xa4, 0xd0, - 0xd3, 0xc2, 0xb8, 0x13, 0x66, 0x8f, 0x3b, 0x31, 0x12, 0x77, 0x73, 0xb6, 0x51, 0x51, 0x59, 0xd3, - 0x73, 0xc8, 0x9a, 0x99, 0x51, 0xd6, 0xdf, 0x0b, 0x90, 0xa6, 0x81, 0x81, 0x6e, 0x8c, 0x1a, 0xef, - 0x74, 0x42, 0xb9, 0xf4, 0x76, 0x58, 0xef, 0xaf, 0x02, 0xe4, 0xfc, 0xa0, 0xfd, 0x5f, 0xb0, 0x9d, - 0x43, 0xc8, 0x54, 0xdb, 0xf9, 0x15, 0xca, 0x5b, 0x61, 0xbb, 0xf0, 0x7e, 0x7e, 0x04, 0x39, 0x3f, - 0x0f, 0x26, 0x5c, 0xef, 0xeb, 0x90, 0x23, 0x3c, 0xc7, 0x26, 0x34, 0x01, 0x91, 0x0c, 0x8c, 0x03, - 0x58, 0x45, 0x83, 0x9c, 0x9f, 0x80, 0x68, 0x51, 0x64, 0xd2, 0xab, 0x42, 0x18, 0x2b, 0x77, 0x82, - 0x14, 0xc5, 0xd6, 0xe7, 0x38, 0xe4, 0x31, 0xe4, 0x29, 0x3d, 0x2d, 0x4f, 0x86, 0xde, 0x24, 0x44, - 0x2a, 0x10, 0xaa, 0x93, 0x9e, 0xad, 0xcf, 0xa6, 0x7b, 0x1f, 0x58, 0xf3, 0x2a, 0xbf, 0xa3, 0xd5, - 0xb1, 0x1f, 0x81, 0xe8, 0xff, 0x22, 0x1f, 0xc1, 0xcf, 0x26, 0x84, 0xa8, 0xff, 0x19, 0x3c, 0xb1, - 0x02, 0x9a, 0xb3, 0xee, 0xb8, 0x0b, 0x05, 0xc3, 0x74, 0x15, 0xf6, 0x25, 0xc9, 0xff, 0x30, 0x3d, - 0xf1, 0x6c, 0xc9, 0x30, 0xdd, 0x7d, 0x87, 0xf4, 0x77, 0x74, 0x54, 0x1f, 0xa9, 0x18, 0x33, 0xcc, - 0x31, 0xaf, 0x25, 0x50, 0x4d, 0xed, 0xd8, 0xf1, 0x2c, 0xe5, 0xde, 0x8d, 0xd1, 0x56, 0x25, 0xea, - 0xfd, 0x81, 0x41, 0x22, 0x35, 0x60, 0xe5, 0x03, 0x80, 0x21, 0xc7, 0x73, 0xd6, 0x7c, 0xe7, 0x20, - 0x6b, 0x3d, 0x7b, 0xe6, 0x12, 0x6e, 0xc5, 0x0c, 0xf6, 0x47, 0x95, 0x7f, 0xfa, 0x9d, 0x0c, 0xb3, - 0xd5, 0x3b, 0x90, 0xb2, 0x2d, 0x37, 0xc1, 0xd3, 0x82, 0xc2, 0x9a, 0x2e, 0x23, 0xe4, 0xa7, 0x28, - 0x6e, 0xa9, 0x58, 0x32, 0x4a, 0x4d, 0x36, 0xdf, 0x8c, 0x21, 0x85, 0xee, 0xc0, 0x62, 0x68, 0x3e, - 0xca, 0x4e, 0x66, 0x22, 0x3b, 0xe0, 0x1b, 0x6f, 0xdf, 0x72, 0x29, 0x07, 0x3a, 0xb1, 0xbd, 0x36, - 0x2b, 0x8e, 0x32, 0x98, 0x0f, 0x62, 0x36, 0xcd, 0x8d, 0xdb, 0xd4, 0x17, 0xfd, 0x73, 0xb7, 0xe9, - 0x3d, 0xde, 0x3a, 0xb1, 0x56, 0x0c, 0x7d, 0x71, 0xf8, 0x0d, 0x6a, 0x4a, 0x3e, 0x0c, 0x30, 0x95, - 0x27, 0x90, 0xf3, 0x35, 0x70, 0xcc, 0xce, 0xd0, 0x85, 0xf4, 0x81, 0x4b, 0x1c, 0x74, 0x32, 0x8c, - 0x59, 0x89, 0x05, 0x67, 0x19, 0xf2, 0x3d, 0x97, 0x38, 0xa6, 0xda, 0x0d, 0xac, 0x1e, 0x8e, 0xd1, - 0xd7, 0x12, 0x2e, 0x9c, 0x72, 0x95, 0xbf, 0x1b, 0x56, 0x83, 0x77, 0x43, 0xc6, 0x07, 0x7b, 0x58, - 0x8c, 0xb0, 0x51, 0xf9, 0xb7, 0x08, 0xb9, 0x7d, 0xc7, 0x62, 0xf5, 0x65, 0xfc, 0x48, 0x04, 0xe9, - 0xc8, 0x71, 0xec, 0x37, 0xba, 0x0c, 0x60, 0xf7, 0x0e, 0x3b, 0x86, 0xc6, 0x1e, 0x17, 0xb9, 0xa7, - 0x49, 0x7c, 0xe6, 0x7d, 0x32, 0xa0, 0xcb, 0x2e, 0xd1, 0x1c, 0xc2, 0xdf, 0x1e, 0xd3, 0x7c, 0x99, - 0xcf, 0xd0, 0xe5, 0x55, 0x28, 0xaa, 0x3d, 0xaf, 0xad, 0x7c, 0x4c, 0x0e, 0xdb, 0x96, 0x75, 0xa4, - 0xf4, 0x9c, 0x8e, 0xff, 0xc5, 0xef, 0x24, 0x9d, 0x7f, 0xc2, 0xa7, 0x0f, 0x9c, 0x0e, 0x5a, 0x87, - 0x33, 0x23, 0xc8, 0x2e, 0xf1, 0xda, 0x96, 0xee, 0x96, 0xb2, 0x2b, 0xa9, 0x55, 0x09, 0xa3, 0x08, - 0xfa, 0x11, 0x5f, 0x41, 0xdf, 0x80, 0x8b, 0xfe, 0x3b, 0x9b, 0x4e, 0x54, 0xcd, 0x33, 0xfa, 0xaa, - 0x47, 0x14, 0xaf, 0xed, 0x10, 0xb7, 0x6d, 0x75, 0x74, 0x56, 0x76, 0x4b, 0xf8, 0x02, 0x87, 0x6c, - 0x85, 0x88, 0x56, 0x00, 0x88, 0x29, 0x31, 0xff, 0x1a, 0x4a, 0xa4, 0xa4, 0x91, 0x14, 0x2d, 0xbd, - 0x9a, 0x74, 0x98, 0xa7, 0x7f, 0x9c, 0x82, 0x73, 0x07, 0x74, 0xa4, 0x1e, 0x76, 0x88, 0x6f, 0x88, - 0xf7, 0x0c, 0xd2, 0xd1, 0x5d, 0xb4, 0xee, 0xab, 0x5f, 0xf0, 0xbf, 0xa5, 0xc4, 0xf7, 0x6b, 0x7a, - 0x8e, 0x61, 0x3e, 0x67, 0x25, 0x89, 0x6f, 0x9c, 0xf7, 0x12, 0xd4, 0x2b, 0xce, 0x40, 0x1d, 0x57, - 0xfe, 0xb3, 0x09, 0xca, 0xe7, 0x9e, 0x75, 0x27, 0xe2, 0xdb, 0xc9, 0xac, 0x57, 0x6b, 0x63, 0xe6, - 0x49, 0x34, 0xd9, 0x77, 0xa6, 0x9b, 0x2c, 0x3d, 0x03, 0xeb, 0x93, 0x0d, 0x5a, 0xae, 0x02, 0x1a, - 0xe7, 0x83, 0xbf, 0xf5, 0x72, 0x71, 0x04, 0xe6, 0x4b, 0xc1, 0xb0, 0xf2, 0x7d, 0x11, 0x96, 0xb6, - 0xfc, 0x67, 0xf2, 0x66, 0xaf, 0xdb, 0x55, 0x9d, 0xc1, 0x58, 0x48, 0x8c, 0x3f, 0x6e, 0xc5, 0x5f, - 0xc5, 0xa5, 0xc8, 0xab, 0xf8, 0xa8, 0x4b, 0xa5, 0x5f, 0xc7, 0xa5, 0xee, 0x43, 0x41, 0xd5, 0x34, - 0xe2, 0xba, 0xd1, 0xe2, 0x6e, 0x1a, 0x2d, 0x04, 0xf0, 0x31, 0x7f, 0xcc, 0xbe, 0x8e, 0x3f, 0xfe, - 0x54, 0x80, 0xfc, 0xbe, 0x43, 0x5c, 0x62, 0x6a, 0xec, 0x46, 0xd1, 0x3a, 0x96, 0x76, 0xc4, 0x14, - 0x90, 0xc1, 0x7c, 0x40, 0x1b, 0x59, 0x6a, 0xf4, 0x92, 0xc8, 0xd2, 0x64, 0xf4, 0x95, 0x32, 0x20, - 0xac, 0x6e, 0xa9, 0x9e, 0xca, 0x73, 0x38, 0x83, 0x96, 0xbf, 0x02, 0x52, 0x38, 0xf5, 0x3a, 0x9f, - 0x5e, 0x2a, 0x3b, 0x90, 0xad, 0x33, 0x03, 0x47, 0x2c, 0xb1, 0xc8, 0x2c, 0xb1, 0x06, 0x79, 0xdb, - 0x3f, 0x2e, 0x21, 0xdd, 0x07, 0x9c, 0xe0, 0x10, 0x54, 0x69, 0x00, 0x0c, 0xff, 0xd8, 0x10, 0x7b, - 0x76, 0x17, 0x92, 0x9e, 0xdd, 0x47, 0x1f, 0xee, 0xc5, 0xd8, 0xc3, 0x7d, 0xe5, 0x87, 0x02, 0x14, - 0x22, 0x9f, 0x84, 0x8f, 0xf7, 0x1a, 0x40, 0xff, 0x0f, 0x4b, 0x0e, 0xe9, 0xa8, 0xb4, 0x97, 0x54, - 0x7c, 0x40, 0x8a, 0x01, 0x4e, 0x06, 0xd3, 0x7b, 0xfc, 0xbe, 0xd0, 0x00, 0x86, 0x3b, 0x47, 0xff, - 0x2a, 0x20, 0x8c, 0xff, 0x55, 0xe0, 0x12, 0x48, 0x3a, 0xe9, 0xd0, 0x16, 0x95, 0x38, 0x81, 0x40, - 0xe1, 0xc4, 0xc8, 0x1f, 0x09, 0x52, 0xa3, 0x7f, 0x24, 0xf8, 0x89, 0x00, 0xf9, 0x2d, 0x4b, 0x93, - 0xfb, 0xd4, 0x12, 0xb7, 0x46, 0xda, 0xa3, 0xf3, 0x11, 0x11, 0x03, 0x48, 0xa4, 0x43, 0x5a, 0x03, - 0x7e, 0x3b, 0xb8, 0x6d, 0xff, 0xc8, 0xd8, 0x5f, 0x43, 0x98, 0x3a, 0xf1, 0x10, 0x83, 0xae, 0x40, - 0xf8, 0x5f, 0x95, 0x80, 0x11, 0x09, 0x43, 0x30, 0xb5, 0xa3, 0xdf, 0xfc, 0x54, 0x04, 0x29, 0xec, - 0xc3, 0xd0, 0x69, 0x58, 0x7a, 0x5c, 0xdb, 0x3d, 0x90, 0x95, 0xd6, 0xd3, 0x7d, 0x59, 0x69, 0x1c, - 0xec, 0xee, 0x16, 0x17, 0xd0, 0x39, 0x40, 0x91, 0xc9, 0xcd, 0xbd, 0xbd, 0x5d, 0xb9, 0xd6, 0x28, - 0x0a, 0xb1, 0xf9, 0x9d, 0x46, 0x4b, 0x7e, 0x20, 0xe3, 0xa2, 0x18, 0xdb, 0x64, 0x77, 0xaf, 0xf1, - 0xa0, 0x98, 0x42, 0x67, 0xe1, 0x54, 0x64, 0x72, 0x6b, 0xef, 0x60, 0x73, 0x57, 0x2e, 0xa6, 0x63, - 0xd3, 0xcd, 0x16, 0xde, 0x69, 0x3c, 0x28, 0x66, 0xd0, 0x19, 0x28, 0x46, 0x8f, 0x7c, 0xda, 0x92, - 0x9b, 0xc5, 0x6c, 0x6c, 0xe3, 0xad, 0x5a, 0x4b, 0x2e, 0xe6, 0x50, 0x19, 0xce, 0x45, 0x26, 0x69, - 0x57, 0xa0, 0xec, 0x6d, 0x3e, 0x94, 0xeb, 0xad, 0x62, 0x1e, 0x5d, 0x80, 0xb3, 0xf1, 0xb5, 0x1a, - 0xc6, 0xb5, 0xa7, 0x45, 0x29, 0xb6, 0x57, 0x4b, 0xfe, 0x76, 0xab, 0x08, 0xb1, 0xbd, 0x7c, 0x89, - 0x94, 0x7a, 0xa3, 0x55, 0x2c, 0xa0, 0xf3, 0x70, 0x3a, 0x26, 0x15, 0x5b, 0x58, 0x8c, 0xef, 0x84, - 0x65, 0xb9, 0x78, 0xe2, 0xe6, 0x2f, 0x04, 0x58, 0x8c, 0xda, 0x0f, 0xbd, 0x03, 0x2b, 0x5b, 0x7b, - 0x75, 0x45, 0x7e, 0x2c, 0x37, 0x5a, 0x81, 0x0e, 0xea, 0x07, 0x8f, 0xe4, 0x46, 0xab, 0xa9, 0xd4, - 0xb7, 0x6b, 0x8d, 0x07, 0xf2, 0x56, 0x71, 0x61, 0x2a, 0xea, 0x49, 0xad, 0x55, 0xdf, 0x96, 0xb7, - 0x8a, 0x02, 0xba, 0x0e, 0x95, 0x89, 0xa8, 0x83, 0x46, 0x80, 0x13, 0xd1, 0x35, 0xb8, 0x12, 0xc3, - 0xed, 0x63, 0xb9, 0x29, 0x37, 0xea, 0x72, 0x78, 0x64, 0x6a, 0xf3, 0xd6, 0x6f, 0x5e, 0x2e, 0x0b, - 0x7f, 0x78, 0xb9, 0x2c, 0xfc, 0xf9, 0xe5, 0xb2, 0xf0, 0xf3, 0xbf, 0x2c, 0x2f, 0xc0, 0x29, 0x9d, - 0xf4, 0x03, 0xa7, 0x52, 0x6d, 0xa3, 0xda, 0xbf, 0xbd, 0x2f, 0x7c, 0x90, 0xae, 0xde, 0xef, 0xdf, - 0x3e, 0xcc, 0xb2, 0x74, 0xf7, 0xa5, 0xff, 0x04, 0x00, 0x00, 0xff, 0xff, 0x9e, 0x7c, 0x09, 0xa2, - 0x8d, 0x25, 0x00, 0x00, + // 2541 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x5a, 0xdd, 0x73, 0xdb, 0x58, + 0x15, 0x8f, 0xe4, 0x4f, 0x9d, 0xa4, 0x89, 0x7b, 0xd3, 0x0f, 0xd7, 0x6d, 0x43, 0xd6, 0x5b, 0x4a, + 0xda, 0x82, 0x93, 0x86, 0x16, 0x96, 0x96, 0x05, 0x1c, 0x5b, 0x6d, 0xd2, 0x4d, 0x9d, 0x20, 0x3b, + 0x2d, 0xdd, 0x81, 0xd1, 0x28, 0xd2, 0x6d, 0xa3, 0x8d, 0x6d, 0x79, 0x25, 0xd9, 0x5b, 0xbf, 0x2e, + 0x30, 0xc3, 0x2b, 0x6f, 0xfc, 0x0b, 0xfc, 0x09, 0xfb, 0x08, 0x0f, 0x0c, 0x33, 0xc0, 0xc0, 0x0c, + 0x3b, 0xc3, 0x2b, 0x5b, 0x1e, 0x18, 0x78, 0x63, 0x18, 0x78, 0x63, 0x86, 0xb9, 0x1f, 0x92, 0xaf, + 0x65, 0xd9, 0x75, 0x4d, 0x66, 0xa7, 0x1d, 0xde, 0x74, 0xef, 0xfd, 0x9d, 0x7b, 0xcf, 0xb9, 0xe7, + 0x77, 0x8e, 0xce, 0xd5, 0x15, 0x5c, 0xe8, 0x3b, 0xee, 0xb1, 0x8d, 0xd7, 0x7b, 0x37, 0xd7, 0x5d, + 0xec, 0x39, 0x5d, 0xd7, 0xc4, 0x5e, 0xa9, 0xe3, 0x3a, 0xbe, 0x83, 0x14, 0x36, 0x54, 0xea, 0xdd, + 0x2c, 0x7c, 0xe1, 0x99, 0xe3, 0x3c, 0x6b, 0xe2, 0x75, 0x3a, 0x70, 0xd8, 0x7d, 0xba, 0xee, 0xdb, + 0x2d, 0xec, 0xf9, 0x46, 0xab, 0xc3, 0xb0, 0x85, 0x95, 0x28, 0xe0, 0x23, 0xd7, 0xe8, 0x74, 0xb0, + 0xcb, 0xe7, 0x2a, 0xfe, 0x46, 0x82, 0x6c, 0xbd, 0x6d, 0x74, 0xbc, 0x23, 0xc7, 0x47, 0xd7, 0x21, + 0xe9, 0x3a, 0x8e, 0x9f, 0x97, 0x56, 0xa5, 0xb5, 0xf9, 0xcd, 0x73, 0xa5, 0x70, 0x9d, 0xd2, 0x83, + 0xfa, 0x5e, 0x4d, 0x6d, 0xe2, 0x16, 0x6e, 0xfb, 0x1a, 0xc5, 0xa0, 0xef, 0x80, 0xd2, 0x71, 0xb1, + 0x87, 0xdb, 0x26, 0xf6, 0xf2, 0xf2, 0x6a, 0x62, 0x6d, 0x7e, 0xb3, 0x28, 0x08, 0x04, 0x73, 0x96, + 0xf6, 0x03, 0x90, 0xda, 0xf6, 0xdd, 0xbe, 0x36, 0x10, 0x2a, 0x7c, 0x17, 0x16, 0x87, 0x07, 0x51, + 0x0e, 0x12, 0xc7, 0xb8, 0x4f, 0x97, 0x57, 0x34, 0xf2, 0x88, 0xae, 0x41, 0xaa, 0x67, 0x34, 0xbb, + 0x38, 0x2f, 0x53, 0x95, 0x96, 0x85, 0x15, 0x02, 0x59, 0x8d, 0x21, 0xee, 0xc8, 0xef, 0x48, 0xc5, + 0x9f, 0xca, 0x00, 0x95, 0x23, 0xa3, 0xfd, 0x0c, 0xef, 0x1b, 0xe6, 0x31, 0x7a, 0x0b, 0x16, 0x2c, + 0xc7, 0xec, 0x12, 0xad, 0xf5, 0xc1, 0xc4, 0xf3, 0x41, 0xdf, 0x7b, 0xb8, 0x8f, 0x6e, 0x03, 0x98, + 0x47, 0xd8, 0x3c, 0xee, 0x38, 0x76, 0xdb, 0xe7, 0xab, 0x9c, 0x15, 0x56, 0xa9, 0x84, 0x83, 0x9a, + 0x00, 0x44, 0x05, 0xc8, 0x7a, 0xdc, 0xc2, 0x7c, 0x62, 0x55, 0x5a, 0x5b, 0xd0, 0xc2, 0x36, 0xba, + 0x01, 0x19, 0x93, 0xea, 0xe0, 0xe5, 0x93, 0x74, 0x5f, 0x4e, 0x0f, 0xcd, 0x47, 0x46, 0xb4, 0x00, + 0x81, 0xca, 0x70, 0xba, 0x65, 0xb7, 0x75, 0xaf, 0xdf, 0x36, 0xb1, 0xa5, 0xfb, 0xb6, 0x79, 0x8c, + 0xfd, 0x7c, 0x6a, 0x44, 0x8d, 0x86, 0xdd, 0xc2, 0x0d, 0x3a, 0xa8, 0x2d, 0xb5, 0xec, 0x76, 0x9d, + 0xc2, 0x59, 0x07, 0xba, 0x0c, 0x60, 0x7b, 0xba, 0x8b, 0x5b, 0x4e, 0x0f, 0x5b, 0xf9, 0xf4, 0xaa, + 0xb4, 0x96, 0xd5, 0x14, 0xdb, 0xd3, 0x58, 0x47, 0xf1, 0x17, 0x12, 0xa4, 0xd9, 0xaa, 0xe8, 0x6d, + 0x90, 0x6d, 0x8b, 0x7b, 0x77, 0x79, 0x44, 0xa9, 0x9d, 0xaa, 0x26, 0xdb, 0x16, 0xca, 0x43, 0xa6, + 0x85, 0x3d, 0xcf, 0x78, 0xc6, 0x36, 0x5d, 0xd1, 0x82, 0x26, 0xba, 0x05, 0xe0, 0x74, 0xb0, 0x6b, + 0xf8, 0xb6, 0xd3, 0xf6, 0xf2, 0x09, 0x6a, 0xdb, 0x19, 0x61, 0x9a, 0xbd, 0x60, 0x50, 0x13, 0x70, + 0x68, 0x0b, 0x96, 0x02, 0x9f, 0xeb, 0xcc, 0xea, 0x7c, 0x92, 0x6a, 0x70, 0x21, 0xc6, 0x99, 0x7c, + 0x7b, 0x16, 0x3b, 0x43, 0xed, 0xe2, 0x8f, 0x25, 0xc8, 0x06, 0x4a, 0x12, 0x7b, 0xcd, 0xa6, 0x4d, + 0x7c, 0xea, 0xe1, 0x0f, 0xa9, 0x35, 0xa7, 0x34, 0x85, 0xf5, 0xd4, 0xf1, 0x87, 0xe8, 0x2d, 0x00, + 0x0f, 0xbb, 0x3d, 0xec, 0xd2, 0x61, 0x62, 0x42, 0x62, 0x4b, 0xde, 0x90, 0x34, 0x85, 0xf5, 0x12, + 0xc8, 0x25, 0xc8, 0x34, 0x8d, 0x56, 0xc7, 0x71, 0x99, 0xf3, 0xd8, 0x78, 0xd0, 0x85, 0x2e, 0x40, + 0xd6, 0x30, 0x7d, 0xc7, 0xd5, 0x6d, 0x8b, 0x6a, 0xba, 0xa0, 0x65, 0x68, 0x7b, 0xc7, 0x2a, 0xfe, + 0xb6, 0x00, 0x4a, 0x68, 0x25, 0xfa, 0x32, 0x24, 0x3c, 0x1c, 0x44, 0x4b, 0x3e, 0x6e, 0x23, 0x4a, + 0x75, 0xec, 0x6f, 0xcf, 0x69, 0x04, 0x46, 0xd0, 0x86, 0x65, 0x71, 0x8a, 0xc5, 0xa3, 0xcb, 0x96, + 0x45, 0xd0, 0x86, 0x65, 0xa1, 0x75, 0x48, 0x12, 0xf7, 0x51, 0xfd, 0x86, 0xb7, 0x6a, 0x00, 0x7f, + 0xe8, 0xf4, 0xf0, 0xf6, 0x9c, 0x46, 0x81, 0xe8, 0x36, 0xa4, 0x19, 0x05, 0xf8, 0xee, 0x5e, 0x8c, + 0x15, 0x61, 0xa4, 0xd8, 0x9e, 0xd3, 0x38, 0x98, 0xac, 0x83, 0x2d, 0x3b, 0xa0, 0x5c, 0xfc, 0x3a, + 0xaa, 0x65, 0x13, 0x2b, 0x28, 0x90, 0xac, 0xe3, 0xe1, 0x26, 0x36, 0x7d, 0xca, 0xb4, 0x71, 0xeb, + 0xd4, 0x29, 0x84, 0xac, 0xc3, 0xc0, 0x68, 0x13, 0x52, 0x9e, 0xdf, 0x6f, 0xe2, 0x7c, 0x86, 0x4a, + 0x15, 0xe2, 0xa5, 0x08, 0x62, 0x7b, 0x4e, 0x63, 0x50, 0x74, 0x17, 0xb2, 0x76, 0xdb, 0x74, 0xb1, + 0xe1, 0xe1, 0x7c, 0x96, 0x8a, 0x5d, 0x8e, 0x15, 0xdb, 0xe1, 0xa0, 0xed, 0x39, 0x2d, 0x14, 0x40, + 0xdf, 0x04, 0xc5, 0x77, 0x31, 0xd6, 0xa9, 0x75, 0xca, 0x04, 0xe9, 0x86, 0x8b, 0x31, 0xb7, 0x30, + 0xeb, 0xf3, 0x67, 0xf4, 0x6d, 0x00, 0x2a, 0xcd, 0x74, 0x06, 0x2a, 0xbe, 0x32, 0x56, 0x3c, 0xd0, + 0x9b, 0xae, 0x48, 0x1b, 0x85, 0x5f, 0x49, 0x90, 0xa8, 0x63, 0x9f, 0xc4, 0x77, 0xc7, 0x70, 0x09, + 0x59, 0x89, 0x5e, 0x3e, 0xb6, 0x74, 0x23, 0x60, 0xcc, 0xb8, 0xf8, 0x66, 0xf8, 0x0a, 0x83, 0x97, + 0xfd, 0x20, 0x2b, 0xca, 0x83, 0xac, 0xb8, 0x19, 0x64, 0x45, 0xc6, 0x8e, 0x4b, 0xf1, 0x89, 0xba, + 0x6e, 0xb7, 0x3a, 0xcd, 0x20, 0x3d, 0xa2, 0xaf, 0xc1, 0x3c, 0x7e, 0x8e, 0xcd, 0x2e, 0x57, 0x21, + 0x39, 0x49, 0x05, 0x08, 0x90, 0x65, 0xbf, 0xf0, 0x4f, 0x09, 0x12, 0x65, 0xcb, 0x3a, 0x09, 0x43, + 0xde, 0xa5, 0x99, 0xa0, 0x27, 0x4e, 0x20, 0x4f, 0x9a, 0xe0, 0x14, 0x41, 0x0f, 0xc4, 0x3f, 0x4f, + 0xab, 0xff, 0x2d, 0x41, 0x92, 0x84, 0xd7, 0x6b, 0x60, 0xf6, 0x2d, 0x00, 0x41, 0x32, 0x31, 0x49, + 0x52, 0x31, 0x43, 0xa9, 0x59, 0x0d, 0xff, 0x44, 0x82, 0x34, 0x4b, 0x12, 0x27, 0x61, 0xfa, 0xb0, + 0xee, 0xf2, 0x6c, 0xba, 0x27, 0xa6, 0xd5, 0xfd, 0x97, 0x49, 0x48, 0xd2, 0xe8, 0x3d, 0x01, 0xcd, + 0xaf, 0x43, 0xf2, 0xa9, 0xeb, 0xb4, 0xb8, 0xce, 0x62, 0x29, 0xd4, 0xc0, 0xcf, 0xfd, 0x9a, 0x63, + 0xe1, 0x7d, 0xc7, 0xd3, 0x28, 0x06, 0x5d, 0x05, 0xd9, 0x77, 0xb8, 0x9a, 0xe3, 0x90, 0xb2, 0xef, + 0xa0, 0x23, 0x38, 0x3f, 0xd0, 0x47, 0x6f, 0x19, 0x1d, 0xfd, 0xb0, 0xaf, 0xd3, 0x57, 0x0b, 0x2f, + 0x14, 0x36, 0xc7, 0xa6, 0xdf, 0x52, 0xa8, 0xd9, 0x43, 0xa3, 0xb3, 0xd5, 0x2f, 0x13, 0x21, 0x56, + 0x50, 0x2d, 0x9b, 0xa3, 0x23, 0xe4, 0x1d, 0x6e, 0x3a, 0x6d, 0x1f, 0xb7, 0x59, 0x62, 0x57, 0xb4, + 0xa0, 0x19, 0xdd, 0xdb, 0xf4, 0x94, 0x7b, 0x8b, 0x76, 0x00, 0x0c, 0xdf, 0x77, 0xed, 0xc3, 0xae, + 0x8f, 0xbd, 0x7c, 0x86, 0xaa, 0x7b, 0x6d, 0xbc, 0xba, 0xe5, 0x10, 0xcb, 0xb4, 0x14, 0x84, 0x0b, + 0x3f, 0x80, 0xfc, 0x38, 0x6b, 0x62, 0x2a, 0xc0, 0x1b, 0xc3, 0x15, 0xe0, 0x18, 0x55, 0x07, 0x35, + 0x60, 0xe1, 0x5d, 0x58, 0x8a, 0xac, 0x1e, 0x33, 0xeb, 0x19, 0x71, 0x56, 0x45, 0x14, 0xff, 0x93, + 0x04, 0x69, 0xf6, 0xf6, 0x7a, 0x5d, 0x69, 0x34, 0x6b, 0x68, 0x7f, 0x26, 0x43, 0x8a, 0xbe, 0x9c, + 0x5e, 0x57, 0xc3, 0x1e, 0x0c, 0x71, 0x8c, 0x85, 0xc4, 0xf5, 0xf1, 0x85, 0xc2, 0x24, 0x92, 0x45, + 0x37, 0x29, 0x35, 0xed, 0x26, 0xfd, 0x8f, 0xec, 0xf9, 0x44, 0x82, 0x6c, 0x50, 0x8e, 0x9c, 0xc4, + 0x36, 0x6f, 0x0e, 0xb3, 0x7f, 0x96, 0x77, 0xde, 0xd4, 0xe9, 0xf3, 0x87, 0x32, 0x64, 0x83, 0x62, + 0xe8, 0x24, 0x74, 0xbf, 0x3a, 0x44, 0x11, 0x24, 0x4a, 0xb9, 0x58, 0xa0, 0x47, 0x51, 0xa0, 0x47, + 0x1c, 0x8a, 0x50, 0x63, 0x03, 0xb2, 0x3c, 0x83, 0x05, 0xc4, 0x38, 0x13, 0x41, 0x12, 0x22, 0x79, + 0x5a, 0x88, 0x9a, 0x99, 0x00, 0x9f, 0xc9, 0xa0, 0x84, 0x35, 0xdd, 0xeb, 0xb6, 0x0d, 0xb5, 0x98, + 0x08, 0x29, 0x4d, 0x2e, 0x4b, 0x5f, 0xc3, 0x28, 0xd9, 0x4a, 0x43, 0xf2, 0xd0, 0xb1, 0xfa, 0xc5, + 0x7f, 0x48, 0x70, 0x7a, 0x84, 0xc6, 0x91, 0xa2, 0x41, 0x9a, 0xb2, 0x68, 0xd8, 0x80, 0x2c, 0x3d, + 0xef, 0xbe, 0xb4, 0xd0, 0xc8, 0x50, 0x18, 0x2b, 0x4e, 0xf8, 0xa1, 0xf9, 0xe5, 0x85, 0x15, 0x07, + 0x96, 0x7d, 0xb4, 0x06, 0x49, 0xbf, 0xdf, 0x61, 0xa7, 0xac, 0xc5, 0x21, 0x16, 0x3e, 0x22, 0xf6, + 0x35, 0xfa, 0x1d, 0xac, 0x51, 0xc4, 0xc0, 0xfe, 0x14, 0x3d, 0x44, 0xb2, 0x46, 0xf1, 0xe7, 0xa7, + 0x60, 0x5e, 0xb0, 0x19, 0x55, 0x61, 0xfe, 0x03, 0xcf, 0x69, 0xeb, 0xce, 0xe1, 0x07, 0xe4, 0x50, + 0xc5, 0xcc, 0x7d, 0x2b, 0x3e, 0xce, 0xe9, 0xf3, 0x1e, 0x05, 0x6e, 0xcf, 0x69, 0x40, 0xe4, 0x58, + 0x0b, 0x95, 0x81, 0xb6, 0x74, 0xc3, 0x75, 0x8d, 0x3e, 0xb7, 0x7f, 0x75, 0xc2, 0x24, 0x65, 0x82, + 0x23, 0x27, 0x16, 0x22, 0x45, 0x1b, 0xec, 0x83, 0x8e, 0xdd, 0xb2, 0x7d, 0x3b, 0x3c, 0x76, 0x8e, + 0x9b, 0x61, 0x3f, 0xc0, 0x91, 0x19, 0x42, 0x21, 0x74, 0x13, 0x92, 0x3e, 0x7e, 0x1e, 0xd0, 0xe8, + 0xe2, 0x18, 0x61, 0x92, 0xf5, 0xc9, 0x69, 0x92, 0x40, 0xd1, 0x1d, 0x52, 0xa8, 0x74, 0xdb, 0x3e, + 0x76, 0x79, 0x29, 0xb2, 0x32, 0x46, 0xaa, 0xc2, 0x50, 0xdb, 0x73, 0x5a, 0x20, 0x40, 0x97, 0x73, + 0x71, 0x70, 0xa2, 0x1c, 0xbb, 0x9c, 0x8b, 0xe9, 0x21, 0x99, 0x40, 0x0b, 0x9f, 0x4a, 0x00, 0x83, + 0x3d, 0x44, 0x6b, 0x90, 0x6a, 0x93, 0xb4, 0x91, 0x97, 0x68, 0x24, 0x89, 0x51, 0xa7, 0x6d, 0x37, + 0x48, 0x46, 0xd1, 0x18, 0x60, 0xc6, 0x42, 0x56, 0xe4, 0x64, 0x62, 0x06, 0x4e, 0x26, 0xa7, 0xe3, + 0x64, 0xe1, 0x8f, 0x12, 0x28, 0xa1, 0x57, 0x27, 0x5a, 0x75, 0xbf, 0xfc, 0xe6, 0x58, 0xf5, 0x37, + 0x09, 0x94, 0x90, 0x69, 0x61, 0xdc, 0x49, 0xd3, 0xc7, 0x9d, 0x2c, 0xc4, 0xdd, 0x8c, 0xc7, 0x28, + 0xd1, 0xd6, 0xe4, 0x0c, 0xb6, 0xa6, 0xa6, 0xb4, 0xf5, 0xf7, 0x12, 0x24, 0x49, 0x60, 0xa0, 0x6b, + 0xc3, 0xce, 0x5b, 0x8e, 0x29, 0x97, 0xde, 0x0c, 0xef, 0xfd, 0x55, 0x82, 0x0c, 0x0f, 0xda, 0xff, + 0x07, 0xdf, 0xb9, 0x18, 0x4f, 0xf4, 0x1d, 0xaf, 0x50, 0xde, 0x08, 0xdf, 0x85, 0xef, 0xe7, 0x87, + 0x90, 0xe1, 0x79, 0x30, 0xe6, 0xf5, 0xbe, 0x01, 0x19, 0xcc, 0x72, 0x6c, 0xcc, 0x21, 0x40, 0xbc, + 0x2f, 0x08, 0x60, 0x45, 0x13, 0x32, 0x3c, 0x01, 0x91, 0xa2, 0xa8, 0x4d, 0x5e, 0x15, 0xd2, 0x48, + 0xb9, 0x13, 0xa4, 0x28, 0x3a, 0x3e, 0xc3, 0x22, 0x8f, 0x20, 0x4b, 0xe4, 0x49, 0x79, 0x32, 0x60, + 0x93, 0x24, 0x54, 0x20, 0x64, 0x4f, 0xba, 0x1d, 0x6b, 0xba, 0xbd, 0xe7, 0xc0, 0xb2, 0x5f, 0xfc, + 0x1d, 0xa9, 0x8e, 0x79, 0x04, 0xa2, 0x2f, 0x0a, 0x1f, 0xd2, 0xcf, 0xc6, 0x84, 0x28, 0xff, 0x94, + 0x1e, 0x5b, 0x01, 0xcd, 0x58, 0x77, 0xdc, 0x86, 0x79, 0xbb, 0xed, 0xe9, 0xf4, 0x4b, 0x12, 0xff, + 0x30, 0x3d, 0x76, 0x6d, 0xc5, 0x6e, 0x7b, 0xfb, 0x2e, 0xee, 0xed, 0x58, 0xa8, 0x32, 0x54, 0x31, + 0xa6, 0x28, 0x31, 0xdf, 0x8e, 0x91, 0x9a, 0x78, 0x62, 0xd7, 0xa6, 0x29, 0xf7, 0x26, 0x5c, 0xd5, + 0x04, 0x0e, 0x11, 0xaf, 0x6a, 0xde, 0x07, 0x18, 0x68, 0x3c, 0x63, 0xcd, 0x77, 0x0e, 0xd2, 0xce, + 0xd3, 0xa7, 0x1e, 0x66, 0x5e, 0x4c, 0x69, 0xbc, 0x55, 0xfc, 0x17, 0x3f, 0xc9, 0x50, 0x5f, 0x5d, + 0x81, 0x44, 0xc7, 0xf1, 0x62, 0x98, 0x16, 0x14, 0xd6, 0x64, 0x18, 0x21, 0x9e, 0xa2, 0x98, 0xa7, + 0x22, 0xc9, 0x28, 0x31, 0xde, 0x7d, 0x53, 0x86, 0x14, 0xba, 0x05, 0x0b, 0xa1, 0xfb, 0x88, 0x3a, + 0xa9, 0xb1, 0xea, 0x00, 0x77, 0xde, 0xbe, 0xe3, 0x11, 0x0d, 0x2c, 0xdc, 0xf1, 0x8f, 0x68, 0x71, + 0x94, 0xd2, 0x58, 0x23, 0xe2, 0xd3, 0xcc, 0xa8, 0x4f, 0xb9, 0xe9, 0x9f, 0xbb, 0x4f, 0xef, 0xb0, + 0xa3, 0x13, 0x3d, 0x8a, 0xa1, 0xaf, 0x0c, 0xbe, 0x41, 0x4d, 0xc8, 0x87, 0x01, 0xa6, 0xf8, 0x18, + 0x32, 0x7c, 0x07, 0x4e, 0x98, 0x0c, 0x2d, 0x48, 0x1e, 0x78, 0xd8, 0x45, 0x8b, 0x61, 0xcc, 0x2a, + 0x34, 0x38, 0x0b, 0x90, 0xed, 0x7a, 0xd8, 0x6d, 0x1b, 0xad, 0xc0, 0xeb, 0x61, 0x1b, 0x7d, 0x23, + 0xe6, 0x85, 0x53, 0x28, 0xb1, 0xab, 0xd4, 0x52, 0x70, 0x95, 0x4a, 0xf5, 0xa0, 0x77, 0xad, 0x82, + 0x1a, 0xc5, 0xff, 0xc8, 0x90, 0xd9, 0x77, 0x1d, 0x5a, 0x5f, 0x46, 0x97, 0x44, 0x90, 0x14, 0x96, + 0xa3, 0xcf, 0xe8, 0x32, 0x40, 0xa7, 0x7b, 0xd8, 0xb4, 0x4d, 0x7a, 0x43, 0xc9, 0x98, 0xa6, 0xb0, + 0x9e, 0xf7, 0x70, 0x9f, 0x0c, 0x7b, 0xd8, 0x74, 0x31, 0xbb, 0xc0, 0x4c, 0xb2, 0x61, 0xd6, 0x43, + 0x86, 0xd7, 0x20, 0x67, 0x74, 0xfd, 0x23, 0xfd, 0x23, 0x7c, 0x78, 0xe4, 0x38, 0xc7, 0x7a, 0xd7, + 0x6d, 0xf2, 0x2f, 0x7e, 0x8b, 0xa4, 0xff, 0x31, 0xeb, 0x3e, 0x70, 0x9b, 0x68, 0x03, 0xce, 0x0c, + 0x21, 0x5b, 0xd8, 0x3f, 0x72, 0x2c, 0x2f, 0x9f, 0x5e, 0x4d, 0xac, 0x29, 0x1a, 0x12, 0xd0, 0x0f, + 0xd9, 0x08, 0xfa, 0x16, 0x5c, 0xe4, 0xf7, 0x6c, 0x16, 0x36, 0x4c, 0xdf, 0xee, 0x19, 0x3e, 0xd6, + 0xfd, 0x23, 0x17, 0x7b, 0x47, 0x4e, 0xd3, 0xa2, 0x65, 0xb7, 0xa2, 0x5d, 0x60, 0x90, 0x6a, 0x88, + 0x68, 0x04, 0x80, 0xc8, 0x26, 0x66, 0x5f, 0x61, 0x13, 0x89, 0xa8, 0x90, 0xa2, 0x95, 0x97, 0x8b, + 0x0e, 0xf2, 0xf4, 0x4f, 0x12, 0x70, 0xee, 0x80, 0xb4, 0x8c, 0xc3, 0x26, 0xe6, 0x8e, 0xb8, 0x67, + 0xe3, 0xa6, 0xe5, 0xa1, 0x0d, 0xbe, 0xfd, 0x12, 0xff, 0x96, 0x12, 0x9d, 0xaf, 0xee, 0xbb, 0x76, + 0xfb, 0x19, 0x2d, 0x49, 0xb8, 0x73, 0xee, 0xc5, 0x6c, 0xaf, 0x3c, 0x85, 0x74, 0x74, 0xf3, 0x9f, + 0x8e, 0xd9, 0x7c, 0xc6, 0xac, 0x5b, 0x02, 0xb7, 0xe3, 0x55, 0x2f, 0x95, 0x47, 0xdc, 0x13, 0xeb, + 0xb2, 0xef, 0x4f, 0x76, 0x59, 0x72, 0x0a, 0xd5, 0xc7, 0x3b, 0xb4, 0x50, 0x02, 0x34, 0xaa, 0x07, + 0xbb, 0x2f, 0x66, 0xe6, 0x48, 0x94, 0x4b, 0x41, 0xb3, 0xf8, 0xb1, 0x0c, 0x4b, 0x55, 0x7e, 0xd7, + 0x5e, 0xef, 0xb6, 0x5a, 0x86, 0xdb, 0x1f, 0x09, 0x89, 0xd1, 0xcb, 0xad, 0xe8, 0xd5, 0xba, 0x22, + 0x5c, 0xad, 0x0f, 0x53, 0x2a, 0xf9, 0x2a, 0x94, 0xba, 0x0b, 0xf3, 0x86, 0x69, 0x62, 0xcf, 0x13, + 0x8b, 0xbb, 0x49, 0xb2, 0x10, 0xc0, 0x47, 0xf8, 0x98, 0x7e, 0x15, 0x3e, 0xfe, 0x5d, 0x1a, 0xfc, + 0xe6, 0xc0, 0xaf, 0xe1, 0xdf, 0x19, 0x2a, 0x87, 0xaf, 0x8c, 0xbd, 0x06, 0xe7, 0xf7, 0xf2, 0x42, + 0x79, 0xbc, 0x0e, 0xd9, 0xe0, 0x66, 0x7c, 0xd2, 0x1f, 0x11, 0x21, 0xa8, 0xd8, 0x0a, 0xfe, 0x87, + 0x20, 0x93, 0xa0, 0x8b, 0x70, 0xbe, 0xb2, 0x5d, 0xae, 0xdd, 0x57, 0xf5, 0xc6, 0x93, 0x7d, 0x55, + 0x3f, 0xa8, 0xd5, 0xf7, 0xd5, 0xca, 0xce, 0xbd, 0x1d, 0xb5, 0x9a, 0x9b, 0x43, 0xcb, 0xb0, 0x24, + 0x0e, 0xee, 0x1f, 0x34, 0x72, 0x12, 0x3a, 0x07, 0x48, 0xec, 0xac, 0xaa, 0xbb, 0x6a, 0x43, 0xcd, + 0xc9, 0xe8, 0x2c, 0x9c, 0x16, 0xfb, 0x2b, 0xbb, 0x6a, 0x59, 0xcb, 0x25, 0x8a, 0x3d, 0xc8, 0x06, + 0x4a, 0x90, 0xe3, 0x39, 0xa1, 0x32, 0x4f, 0xfe, 0x97, 0x63, 0xf4, 0x2c, 0x55, 0x0d, 0xdf, 0x60, + 0x6f, 0x26, 0x0a, 0x2d, 0x7c, 0x1d, 0x94, 0xb0, 0xeb, 0x55, 0x3e, 0x28, 0x15, 0x6b, 0xc4, 0xcc, + 0xf0, 0xe7, 0x8c, 0xe1, 0x3f, 0x00, 0xa4, 0xb8, 0x3f, 0x00, 0x86, 0xff, 0x21, 0x90, 0x23, 0xff, + 0x10, 0x14, 0x7f, 0x24, 0xc1, 0xbc, 0xf0, 0x75, 0xfa, 0x64, 0xdf, 0x48, 0xe8, 0x4b, 0xb0, 0xe4, + 0xe2, 0xa6, 0x41, 0x8e, 0xb5, 0x3a, 0x07, 0x24, 0x28, 0x60, 0x31, 0xe8, 0xde, 0x63, 0xaf, 0x2e, + 0x13, 0x60, 0x30, 0xb3, 0xf8, 0xd7, 0x82, 0x34, 0xfa, 0xd7, 0xc2, 0x25, 0x50, 0x2c, 0xdc, 0x24, + 0xa7, 0x65, 0xec, 0x06, 0x06, 0x85, 0x1d, 0x43, 0xff, 0x34, 0x24, 0x86, 0xff, 0x69, 0x38, 0x80, + 0x6c, 0xd5, 0x31, 0xd5, 0x1e, 0x6e, 0xfb, 0xe8, 0xc6, 0x10, 0x33, 0xcf, 0x0b, 0x16, 0x06, 0x10, + 0x81, 0x8c, 0x97, 0x80, 0xbd, 0xa7, 0xbc, 0x23, 0xbe, 0xe2, 0x82, 0x36, 0xe8, 0xb8, 0xfe, 0xa9, + 0x0c, 0x4a, 0x78, 0xba, 0x23, 0xe4, 0x7a, 0x54, 0xde, 0x3d, 0xe0, 0x74, 0xa9, 0x1d, 0xec, 0xee, + 0xe6, 0xe6, 0x08, 0xb9, 0x84, 0xce, 0xad, 0xbd, 0xbd, 0x5d, 0xb5, 0x5c, 0x63, 0xa4, 0x13, 0xfa, + 0x77, 0x6a, 0x0d, 0xf5, 0xbe, 0xaa, 0xe5, 0xe4, 0xc8, 0x24, 0xbb, 0x7b, 0xb5, 0xfb, 0xb9, 0x04, + 0x61, 0xa2, 0xd0, 0x59, 0xdd, 0x3b, 0xd8, 0xda, 0x55, 0x73, 0xc9, 0x48, 0x77, 0xbd, 0xa1, 0xed, + 0xd4, 0xee, 0xe7, 0x52, 0xe8, 0x0c, 0xe4, 0xc4, 0x25, 0x9f, 0x34, 0xd4, 0x7a, 0x2e, 0x1d, 0x99, + 0xb8, 0x5a, 0x6e, 0xa8, 0xb9, 0x0c, 0x2a, 0xc0, 0x39, 0xa1, 0x93, 0x9c, 0x35, 0xf4, 0xbd, 0xad, + 0x07, 0x6a, 0xa5, 0x91, 0xcb, 0xa2, 0x0b, 0x70, 0x36, 0x3a, 0x56, 0xd6, 0xb4, 0xf2, 0x93, 0x9c, + 0x12, 0x99, 0xab, 0xa1, 0x7e, 0xaf, 0x91, 0x83, 0xc8, 0x5c, 0xdc, 0x22, 0xbd, 0x52, 0x6b, 0xe4, + 0xe6, 0xd1, 0x79, 0x58, 0x8e, 0x58, 0x45, 0x07, 0x16, 0xa2, 0x33, 0x69, 0xaa, 0x9a, 0x3b, 0x75, + 0xfd, 0x63, 0x09, 0x16, 0x44, 0x5f, 0xa0, 0x2b, 0xb0, 0x5a, 0xdd, 0xab, 0xe8, 0xea, 0x23, 0xb5, + 0xd6, 0x08, 0xf6, 0xa0, 0x72, 0xf0, 0x50, 0xad, 0x35, 0xea, 0x3a, 0x0b, 0x51, 0x12, 0xdc, 0x93, + 0x50, 0x8f, 0xcb, 0x8d, 0xca, 0xb6, 0x5a, 0xcd, 0x49, 0xe8, 0x2a, 0x14, 0xc7, 0xa2, 0x0e, 0x6a, + 0x01, 0x4e, 0xde, 0xba, 0xf1, 0xeb, 0x17, 0x2b, 0xd2, 0x1f, 0x5e, 0xac, 0x48, 0x7f, 0x7e, 0xb1, + 0x22, 0xfd, 0xec, 0x2f, 0x2b, 0x73, 0x70, 0xda, 0xc2, 0xbd, 0x80, 0x2d, 0x46, 0xc7, 0x2e, 0xf5, + 0x6e, 0xee, 0x4b, 0xef, 0x27, 0x4b, 0x77, 0x7b, 0x37, 0x0f, 0xd3, 0x34, 0x3f, 0x7e, 0xf5, 0xbf, + 0x01, 0x00, 0x00, 0xff, 0xff, 0xfc, 0xa8, 0x34, 0x19, 0xd1, 0x26, 0x00, 0x00, +} + +func (m *Snapshot) 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 *Snapshot) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Snapshot) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Presences) > 0 { + for k := range m.Presences { + v := m.Presences[k] + baseI := i + if v != nil { + { + size, err := v.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintResources(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintResources(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintResources(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x12 + } + } + if m.Root != nil { + { + size, err := m.Root.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintResources(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func (m *ChangePack) Marshal() (dAtA []byte, err error) { @@ -3494,6 +3645,18 @@ func (m *Change) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.PresenceChange != nil { + { + size, err := m.PresenceChange.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintResources(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } if len(m.Operations) > 0 { for iNdEx := len(m.Operations) - 1; iNdEx >= 0; iNdEx-- { { @@ -6171,7 +6334,7 @@ func (m *DocumentSummary) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *Presence) Marshal() (dAtA []byte, err error) { +func (m *PresenceChange) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -6181,12 +6344,12 @@ func (m *Presence) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *Presence) MarshalTo(dAtA []byte) (int, error) { +func (m *PresenceChange) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *Presence) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *PresenceChange) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -6195,34 +6358,27 @@ func (m *Presence) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } - if len(m.Data) > 0 { - for k := range m.Data { - v := m.Data[k] - baseI := i - i -= len(v) - copy(dAtA[i:], v) - i = encodeVarintResources(dAtA, i, uint64(len(v))) - i-- - dAtA[i] = 0x12 - i -= len(k) - copy(dAtA[i:], k) - i = encodeVarintResources(dAtA, i, uint64(len(k))) - i-- - dAtA[i] = 0xa - i = encodeVarintResources(dAtA, i, uint64(baseI-i)) - i-- - dAtA[i] = 0x12 + if m.Presence != nil { + { + size, err := m.Presence.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintResources(dAtA, i, uint64(size)) } + i-- + dAtA[i] = 0x12 } - if m.Clock != 0 { - i = encodeVarintResources(dAtA, i, uint64(m.Clock)) + if m.Type != 0 { + i = encodeVarintResources(dAtA, i, uint64(m.Type)) i-- dAtA[i] = 0x8 } return len(dAtA) - i, nil } -func (m *Client) Marshal() (dAtA []byte, err error) { +func (m *Presence) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -6232,12 +6388,12 @@ func (m *Client) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *Client) MarshalTo(dAtA []byte) (int, error) { +func (m *Presence) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *Client) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *Presence) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -6246,24 +6402,24 @@ func (m *Client) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } - if m.Presence != nil { - { - size, err := m.Presence.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintResources(dAtA, i, uint64(size)) + if len(m.Data) > 0 { + for k := range m.Data { + v := m.Data[k] + baseI := i + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintResources(dAtA, i, uint64(len(v))) + i-- + dAtA[i] = 0x12 + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintResources(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintResources(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0xa } - i-- - dAtA[i] = 0x12 - } - if len(m.Id) > 0 { - i -= len(m.Id) - copy(dAtA[i:], m.Id) - i = encodeVarintResources(dAtA, i, uint64(len(m.Id))) - i-- - dAtA[i] = 0xa } return len(dAtA) - i, nil } @@ -6422,22 +6578,10 @@ func (m *DocEvent) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } - if len(m.DocumentId) > 0 { - i -= len(m.DocumentId) - copy(dAtA[i:], m.DocumentId) - i = encodeVarintResources(dAtA, i, uint64(len(m.DocumentId))) - i-- - dAtA[i] = 0x1a - } - if m.Publisher != nil { - { - size, err := m.Publisher.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintResources(dAtA, i, uint64(size)) - } + if len(m.Publisher) > 0 { + i -= len(m.Publisher) + copy(dAtA[i:], m.Publisher) + i = encodeVarintResources(dAtA, i, uint64(len(m.Publisher))) i-- dAtA[i] = 0x12 } @@ -6460,6 +6604,35 @@ func encodeVarintResources(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } +func (m *Snapshot) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Root != nil { + l = m.Root.Size() + n += 1 + l + sovResources(uint64(l)) + } + if len(m.Presences) > 0 { + for k, v := range m.Presences { + _ = k + _ = v + l = 0 + if v != nil { + l = v.Size() + l += 1 + sovResources(uint64(l)) + } + mapEntrySize := 1 + len(k) + sovResources(uint64(len(k))) + l + n += mapEntrySize + 1 + sovResources(uint64(mapEntrySize)) + } + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + func (m *ChangePack) Size() (n int) { if m == nil { return 0 @@ -6517,6 +6690,10 @@ func (m *Change) Size() (n int) { n += 1 + l + sovResources(uint64(l)) } } + if m.PresenceChange != nil { + l = m.PresenceChange.Size() + n += 1 + l + sovResources(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -7663,22 +7840,18 @@ func (m *DocumentSummary) Size() (n int) { return n } -func (m *Presence) Size() (n int) { +func (m *PresenceChange) Size() (n int) { if m == nil { return 0 } var l int _ = l - if m.Clock != 0 { - n += 1 + sovResources(uint64(m.Clock)) + if m.Type != 0 { + n += 1 + sovResources(uint64(m.Type)) } - if len(m.Data) > 0 { - for k, v := range m.Data { - _ = k - _ = v - mapEntrySize := 1 + len(k) + sovResources(uint64(len(k))) + 1 + len(v) + sovResources(uint64(len(v))) - n += mapEntrySize + 1 + sovResources(uint64(mapEntrySize)) - } + if m.Presence != nil { + l = m.Presence.Size() + n += 1 + l + sovResources(uint64(l)) } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) @@ -7686,19 +7859,19 @@ func (m *Presence) Size() (n int) { return n } -func (m *Client) Size() (n int) { +func (m *Presence) Size() (n int) { if m == nil { return 0 } var l int _ = l - l = len(m.Id) - if l > 0 { - n += 1 + l + sovResources(uint64(l)) - } - if m.Presence != nil { - l = m.Presence.Size() - n += 1 + l + sovResources(uint64(l)) + if len(m.Data) > 0 { + for k, v := range m.Data { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovResources(uint64(len(k))) + 1 + len(v) + sovResources(uint64(len(v))) + n += mapEntrySize + 1 + sovResources(uint64(mapEntrySize)) + } } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) @@ -7777,11 +7950,7 @@ func (m *DocEvent) Size() (n int) { if m.Type != 0 { n += 1 + sovResources(uint64(m.Type)) } - if m.Publisher != nil { - l = m.Publisher.Size() - n += 1 + l + sovResources(uint64(l)) - } - l = len(m.DocumentId) + l = len(m.Publisher) if l > 0 { n += 1 + l + sovResources(uint64(l)) } @@ -7797,6 +7966,222 @@ func sovResources(x uint64) (n int) { func sozResources(x uint64) (n int) { return sovResources(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } +func (m *Snapshot) 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 ErrIntOverflowResources + } + 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: Snapshot: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Snapshot: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Root", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowResources + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthResources + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthResources + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Root == nil { + m.Root = &JSONElement{} + } + if err := m.Root.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Presences", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowResources + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthResources + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthResources + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Presences == nil { + m.Presences = make(map[string]*Presence) + } + var mapkey string + var mapvalue *Presence + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowResources + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowResources + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthResources + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthResources + } + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + } else if fieldNum == 2 { + var mapmsglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowResources + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + mapmsglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if mapmsglen < 0 { + return ErrInvalidLengthResources + } + postmsgIndex := iNdEx + mapmsglen + if postmsgIndex < 0 { + return ErrInvalidLengthResources + } + if postmsgIndex > l { + return io.ErrUnexpectedEOF + } + mapvalue = &Presence{} + if err := mapvalue.Unmarshal(dAtA[iNdEx:postmsgIndex]); err != nil { + return err + } + iNdEx = postmsgIndex + } else { + iNdEx = entryPreIndex + skippy, err := skipResources(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthResources + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.Presences[mapkey] = mapvalue + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipResources(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthResources + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *ChangePack) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -8135,11 +8520,45 @@ func (m *Change) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Message = string(dAtA[iNdEx:postIndex]) + m.Message = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Operations", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowResources + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthResources + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthResources + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Operations = append(m.Operations, &Operation{}) + if err := m.Operations[len(m.Operations)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex - case 3: + case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Operations", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field PresenceChange", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -8166,8 +8585,10 @@ func (m *Change) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Operations = append(m.Operations, &Operation{}) - if err := m.Operations[len(m.Operations)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if m.PresenceChange == nil { + m.PresenceChange = &PresenceChange{} + } + if err := m.PresenceChange.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -15235,7 +15656,7 @@ func (m *DocumentSummary) Unmarshal(dAtA []byte) error { } return nil } -func (m *Presence) Unmarshal(dAtA []byte) error { +func (m *PresenceChange) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -15258,17 +15679,17 @@ func (m *Presence) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: Presence: wiretype end group for non-group") + return fmt.Errorf("proto: PresenceChange: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: Presence: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: PresenceChange: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Clock", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) } - m.Clock = 0 + m.Type = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowResources @@ -15278,12 +15699,99 @@ func (m *Presence) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Clock |= int32(b&0x7F) << shift + m.Type |= PresenceChange_ChangeType(b&0x7F) << shift if b < 0x80 { break } } case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Presence", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowResources + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthResources + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthResources + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Presence == nil { + m.Presence = &Presence{} + } + if err := m.Presence.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipResources(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthResources + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Presence) 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 ErrIntOverflowResources + } + 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: Presence: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Presence: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) } @@ -15432,127 +15940,6 @@ func (m *Presence) Unmarshal(dAtA []byte) error { } return nil } -func (m *Client) 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 ErrIntOverflowResources - } - 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: Client: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Client: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowResources - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthResources - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthResources - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Id = append(m.Id[:0], dAtA[iNdEx:postIndex]...) - if m.Id == nil { - m.Id = []byte{} - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Presence", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowResources - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthResources - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthResources - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Presence == nil { - m.Presence = &Presence{} - } - if err := m.Presence.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipResources(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthResources - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func (m *Checkpoint) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -15942,7 +16329,7 @@ func (m *DocEvent) Unmarshal(dAtA []byte) error { if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Publisher", wireType) } - var msglen int + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowResources @@ -15952,59 +16339,25 @@ func (m *DocEvent) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + if byteLen < 0 { return ErrInvalidLengthResources } - postIndex := iNdEx + msglen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthResources } if postIndex > l { return io.ErrUnexpectedEOF } + m.Publisher = append(m.Publisher[:0], dAtA[iNdEx:postIndex]...) if m.Publisher == nil { - m.Publisher = &Client{} - } - if err := m.Publisher.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DocumentId", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowResources - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthResources - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthResources - } - if postIndex > l { - return io.ErrUnexpectedEOF + m.Publisher = []byte{} } - m.DocumentId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex diff --git a/api/yorkie/v1/resources.proto b/api/yorkie/v1/resources.proto index d695f363a..46d879aad 100644 --- a/api/yorkie/v1/resources.proto +++ b/api/yorkie/v1/resources.proto @@ -25,6 +25,14 @@ option go_package = ".;v1"; option java_multiple_files = true; option java_package = "dev.yorkie.api.v1"; +///////////////////////////////////////// +// Messages for Snapshot // +///////////////////////////////////////// +message Snapshot { + JSONElement root = 1; + map presences = 2; +} + ///////////////////////////////////////// // Messages for ChangePack // ///////////////////////////////////////// @@ -44,6 +52,7 @@ message Change { ChangeID id = 1; string message = 2; repeated Operation operations = 3; + PresenceChange presence_change = 4; } message ChangeID { @@ -284,14 +293,19 @@ message DocumentSummary { google.protobuf.Timestamp updated_at = 6; } -message Presence { - int32 clock = 1; - map data = 2; +message PresenceChange { + enum ChangeType { + CHANGE_TYPE_UNSPECIFIED = 0; + CHANGE_TYPE_PUT = 1; + CHANGE_TYPE_DELETE = 2; + CHANGE_TYPE_CLEAR = 3; + } + ChangeType type = 1; + Presence presence = 2; } -message Client { - bytes id = 1; - Presence presence = 2; +message Presence { + map data = 1; } message Checkpoint { @@ -332,11 +346,9 @@ enum DocEventType { DOC_EVENT_TYPE_DOCUMENTS_CHANGED = 0; DOC_EVENT_TYPE_DOCUMENTS_WATCHED = 1; DOC_EVENT_TYPE_DOCUMENTS_UNWATCHED = 2; - DOC_EVENT_TYPE_PRESENCE_CHANGED = 3; } message DocEvent { DocEventType type = 1; - Client publisher = 2; - string document_id = 3; + bytes publisher = 2; } diff --git a/api/yorkie/v1/yorkie.pb.go b/api/yorkie/v1/yorkie.pb.go index 543a706b5..0bd73bedd 100644 --- a/api/yorkie/v1/yorkie.pb.go +++ b/api/yorkie/v1/yorkie.pb.go @@ -467,7 +467,7 @@ func (m *DetachDocumentResponse) GetChangePack() *ChangePack { } type WatchDocumentRequest struct { - Client *Client `protobuf:"bytes,1,opt,name=client,proto3" json:"client,omitempty"` + ClientId []byte `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` DocumentId string `protobuf:"bytes,2,opt,name=document_id,json=documentId,proto3" json:"document_id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -507,9 +507,9 @@ func (m *WatchDocumentRequest) XXX_DiscardUnknown() { var xxx_messageInfo_WatchDocumentRequest proto.InternalMessageInfo -func (m *WatchDocumentRequest) GetClient() *Client { +func (m *WatchDocumentRequest) GetClientId() []byte { if m != nil { - return m.Client + return m.ClientId } return nil } @@ -610,10 +610,10 @@ func (*WatchDocumentResponse) XXX_OneofWrappers() []interface{} { } type WatchDocumentResponse_Initialization struct { - Peers []*Client `protobuf:"bytes,1,rep,name=peers,proto3" json:"peers,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + ClientIds [][]byte `protobuf:"bytes,1,rep,name=client_ids,json=clientIds,proto3" json:"client_ids,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *WatchDocumentResponse_Initialization) Reset() { *m = WatchDocumentResponse_Initialization{} } @@ -649,9 +649,9 @@ func (m *WatchDocumentResponse_Initialization) XXX_DiscardUnknown() { var xxx_messageInfo_WatchDocumentResponse_Initialization proto.InternalMessageInfo -func (m *WatchDocumentResponse_Initialization) GetPeers() []*Client { +func (m *WatchDocumentResponse_Initialization) GetClientIds() [][]byte { if m != nil { - return m.Peers + return m.ClientIds } return nil } @@ -900,100 +900,6 @@ func (m *PushPullChangesResponse) GetChangePack() *ChangePack { return nil } -type UpdatePresenceRequest struct { - Client *Client `protobuf:"bytes,1,opt,name=client,proto3" json:"client,omitempty"` - DocumentId string `protobuf:"bytes,2,opt,name=document_id,json=documentId,proto3" json:"document_id,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *UpdatePresenceRequest) Reset() { *m = UpdatePresenceRequest{} } -func (m *UpdatePresenceRequest) String() string { return proto.CompactTextString(m) } -func (*UpdatePresenceRequest) ProtoMessage() {} -func (*UpdatePresenceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_40070c858814ab24, []int{14} -} -func (m *UpdatePresenceRequest) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *UpdatePresenceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_UpdatePresenceRequest.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 *UpdatePresenceRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_UpdatePresenceRequest.Merge(m, src) -} -func (m *UpdatePresenceRequest) XXX_Size() int { - return m.Size() -} -func (m *UpdatePresenceRequest) XXX_DiscardUnknown() { - xxx_messageInfo_UpdatePresenceRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_UpdatePresenceRequest proto.InternalMessageInfo - -func (m *UpdatePresenceRequest) GetClient() *Client { - if m != nil { - return m.Client - } - return nil -} - -func (m *UpdatePresenceRequest) GetDocumentId() string { - if m != nil { - return m.DocumentId - } - return "" -} - -type UpdatePresenceResponse struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *UpdatePresenceResponse) Reset() { *m = UpdatePresenceResponse{} } -func (m *UpdatePresenceResponse) String() string { return proto.CompactTextString(m) } -func (*UpdatePresenceResponse) ProtoMessage() {} -func (*UpdatePresenceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_40070c858814ab24, []int{15} -} -func (m *UpdatePresenceResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *UpdatePresenceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_UpdatePresenceResponse.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 *UpdatePresenceResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_UpdatePresenceResponse.Merge(m, src) -} -func (m *UpdatePresenceResponse) XXX_Size() int { - return m.Size() -} -func (m *UpdatePresenceResponse) XXX_DiscardUnknown() { - xxx_messageInfo_UpdatePresenceResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_UpdatePresenceResponse proto.InternalMessageInfo - func init() { proto.RegisterType((*ActivateClientRequest)(nil), "yorkie.v1.ActivateClientRequest") proto.RegisterType((*ActivateClientResponse)(nil), "yorkie.v1.ActivateClientResponse") @@ -1010,59 +916,54 @@ func init() { proto.RegisterType((*RemoveDocumentResponse)(nil), "yorkie.v1.RemoveDocumentResponse") proto.RegisterType((*PushPullChangesRequest)(nil), "yorkie.v1.PushPullChangesRequest") proto.RegisterType((*PushPullChangesResponse)(nil), "yorkie.v1.PushPullChangesResponse") - proto.RegisterType((*UpdatePresenceRequest)(nil), "yorkie.v1.UpdatePresenceRequest") - proto.RegisterType((*UpdatePresenceResponse)(nil), "yorkie.v1.UpdatePresenceResponse") } func init() { proto.RegisterFile("yorkie/v1/yorkie.proto", fileDescriptor_40070c858814ab24) } var fileDescriptor_40070c858814ab24 = []byte{ - // 712 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x56, 0xdd, 0x6e, 0xd3, 0x4c, - 0x10, 0xcd, 0x7e, 0xfd, 0x51, 0x33, 0xf9, 0x1a, 0xe8, 0x16, 0xbb, 0x21, 0x15, 0x69, 0x30, 0x17, - 0x14, 0x55, 0x4a, 0x49, 0x2b, 0x15, 0x21, 0xae, 0xda, 0x06, 0xa9, 0x15, 0x12, 0x44, 0xe6, 0xa7, - 0x6a, 0x25, 0x64, 0xb9, 0xf6, 0x94, 0x58, 0x71, 0xbd, 0xc6, 0x76, 0x2c, 0x85, 0x77, 0x80, 0x6b, - 0xde, 0x81, 0xb7, 0xe0, 0x8a, 0x4b, 0xde, 0x00, 0x14, 0x5e, 0x04, 0xc5, 0xeb, 0x86, 0xac, 0xb3, - 0xa4, 0xa1, 0x52, 0x04, 0x77, 0xf6, 0xee, 0x9c, 0x33, 0x67, 0x8e, 0x77, 0x76, 0x0c, 0x6a, 0x97, - 0x05, 0x6d, 0x07, 0x37, 0xe3, 0xfa, 0x26, 0x7f, 0xaa, 0xf9, 0x01, 0x8b, 0x18, 0xcd, 0xa7, 0x6f, - 0x71, 0xbd, 0x7c, 0xf3, 0x57, 0x48, 0x80, 0x21, 0xeb, 0x04, 0x16, 0x86, 0x3c, 0x4a, 0xdb, 0x01, - 0x65, 0xd7, 0x8a, 0x9c, 0xd8, 0x8c, 0x70, 0xdf, 0x75, 0xd0, 0x8b, 0x74, 0x7c, 0xdb, 0xc1, 0x30, - 0xa2, 0xb7, 0x00, 0xac, 0x64, 0xc1, 0x68, 0x63, 0xb7, 0x44, 0xaa, 0x64, 0x3d, 0xaf, 0xe7, 0xf9, - 0xca, 0x13, 0xec, 0x6a, 0x2f, 0x40, 0xcd, 0xe2, 0x42, 0x9f, 0x79, 0x21, 0x5e, 0x02, 0xa4, 0xab, - 0x90, 0xbe, 0x18, 0x8e, 0x5d, 0xfa, 0xaf, 0x4a, 0xd6, 0xff, 0xd7, 0x17, 0xf8, 0xc2, 0xa1, 0xad, - 0xed, 0xc0, 0x4a, 0x03, 0x4d, 0xa9, 0x1e, 0x01, 0x47, 0x32, 0xb8, 0x07, 0x50, 0x1a, 0xc5, 0xa5, - 0x7a, 0xc6, 0x02, 0x5d, 0x50, 0x76, 0xa3, 0xc8, 0xb4, 0x5a, 0x0d, 0x66, 0x75, 0xce, 0x27, 0x4c, - 0x47, 0x77, 0xa0, 0x60, 0xb5, 0x4c, 0xef, 0x0d, 0x1a, 0xbe, 0x69, 0xb5, 0x93, 0x2a, 0x0a, 0x5b, - 0x4a, 0x6d, 0x60, 0x78, 0x6d, 0x3f, 0xd9, 0x6d, 0x9a, 0x56, 0x5b, 0x07, 0x6b, 0xf0, 0xac, 0x7d, - 0x20, 0xa0, 0x66, 0xd3, 0x4d, 0xa0, 0x92, 0xae, 0x41, 0xc1, 0x4e, 0x01, 0x17, 0xae, 0xe5, 0x75, - 0xb8, 0x58, 0x1a, 0x15, 0x34, 0x33, 0xa9, 0xa0, 0xcf, 0x04, 0x94, 0x06, 0xfe, 0x71, 0xfd, 0xd3, - 0xd2, 0x43, 0xb7, 0x41, 0x0d, 0xf0, 0x9c, 0xc5, 0x68, 0x38, 0x67, 0x86, 0xc7, 0x22, 0xc3, 0x4c, - 0xdc, 0x42, 0xbb, 0x34, 0x5b, 0x25, 0xeb, 0x0b, 0xfa, 0x32, 0xdf, 0x3d, 0x3c, 0x7b, 0xca, 0xa2, - 0xdd, 0x74, 0x4b, 0x63, 0xa0, 0x66, 0x6b, 0x98, 0xec, 0x28, 0x5e, 0xf5, 0x33, 0x9e, 0xc2, 0x8d, - 0x23, 0x33, 0x1a, 0xf5, 0xec, 0x1e, 0xcc, 0x73, 0xf2, 0x24, 0x55, 0x61, 0x6b, 0x69, 0x98, 0x8a, - 0x1f, 0xca, 0x34, 0xe0, 0x52, 0x07, 0xb5, 0x1e, 0x01, 0x25, 0x93, 0x24, 0x2d, 0xea, 0x18, 0x8a, - 0x8e, 0xe7, 0x44, 0x8e, 0xe9, 0x3a, 0xef, 0xcc, 0xc8, 0x61, 0x5e, 0x9a, 0x6d, 0x73, 0x28, 0x9b, - 0x14, 0x59, 0x3b, 0x14, 0x60, 0x07, 0x39, 0x3d, 0x43, 0x44, 0x37, 0x60, 0x0e, 0xe3, 0xbe, 0x7e, - 0x6e, 0xc5, 0xf2, 0x10, 0x63, 0x83, 0x59, 0x8f, 0xfb, 0x5b, 0x07, 0x39, 0x9d, 0xc7, 0x94, 0x1f, - 0x42, 0x51, 0x24, 0xa4, 0x77, 0x61, 0xce, 0x47, 0x0c, 0xc2, 0x12, 0xa9, 0xce, 0xc8, 0xcb, 0xe7, - 0xfb, 0x7b, 0xf3, 0x30, 0x7b, 0xca, 0xec, 0xae, 0xf6, 0x9e, 0x80, 0xa2, 0x27, 0x5f, 0xf4, 0x9f, - 0x38, 0x7e, 0xfd, 0x93, 0x94, 0x95, 0x33, 0xdd, 0x93, 0xf4, 0x89, 0x80, 0xda, 0xec, 0x84, 0xad, - 0x66, 0xc7, 0x75, 0x79, 0x48, 0xf8, 0x77, 0x1b, 0x70, 0x15, 0xf2, 0x7e, 0x27, 0x6c, 0x19, 0xcc, - 0x73, 0xbb, 0x69, 0xcf, 0x2d, 0xf4, 0x17, 0x9e, 0x79, 0x6e, 0x57, 0xf3, 0x60, 0x65, 0x44, 0xec, - 0x24, 0xd7, 0xd7, 0x55, 0xdd, 0xb1, 0x40, 0x79, 0xe9, 0xdb, 0x66, 0x84, 0xcd, 0x00, 0x43, 0xf4, - 0x2c, 0x9c, 0x46, 0xa3, 0x95, 0x40, 0xcd, 0x26, 0xe1, 0x35, 0x6d, 0x7d, 0x9b, 0x83, 0xc5, 0xe3, - 0x84, 0xf7, 0x39, 0x06, 0xb1, 0x63, 0x21, 0x3d, 0x82, 0xa2, 0x38, 0xf4, 0x68, 0x75, 0x28, 0xb3, - 0x74, 0x8e, 0x96, 0x6f, 0x8f, 0x89, 0xe0, 0x89, 0xb4, 0x1c, 0x7d, 0x0d, 0xd7, 0xb3, 0xf3, 0x8b, - 0x6a, 0xc3, 0xdd, 0x27, 0x1f, 0x8a, 0xe5, 0x3b, 0x63, 0x63, 0x06, 0xf4, 0x47, 0x50, 0x14, 0x6b, - 0x14, 0x74, 0x4b, 0x3d, 0x16, 0x74, 0xcb, 0x0d, 0xe2, 0xc4, 0xe2, 0x3c, 0x13, 0x0d, 0x91, 0x4d, - 0x56, 0xd1, 0x10, 0xe9, 0x30, 0xe4, 0xc4, 0xe2, 0x9d, 0x2e, 0x10, 0x4b, 0x47, 0x96, 0x40, 0x2c, - 0x1f, 0x08, 0x9c, 0x58, 0x6c, 0x71, 0x81, 0x58, 0x7a, 0x19, 0x09, 0xc4, 0xf2, 0xfb, 0x41, 0xcb, - 0xd1, 0x13, 0xb8, 0x96, 0x69, 0x0e, 0x3a, 0x8c, 0x93, 0x77, 0x79, 0x59, 0x1b, 0x17, 0x32, 0xe0, - 0x7e, 0x05, 0x8b, 0xc2, 0x8d, 0x4e, 0xd7, 0x7e, 0x7f, 0xd7, 0x73, 0xde, 0xea, 0x65, 0xc3, 0x40, - 0xcb, 0xdd, 0x27, 0x7b, 0x1b, 0x5f, 0x7a, 0x15, 0xf2, 0xb5, 0x57, 0x21, 0xdf, 0x7b, 0x15, 0xf2, - 0xf1, 0x47, 0x25, 0x07, 0x4b, 0x36, 0xc6, 0x17, 0x50, 0xd3, 0x77, 0x6a, 0x71, 0xbd, 0x49, 0x4e, - 0x66, 0x6b, 0x8f, 0xe2, 0xfa, 0xe9, 0x7c, 0xf2, 0xc3, 0xb8, 0xfd, 0x33, 0x00, 0x00, 0xff, 0xff, - 0xe0, 0x36, 0xe4, 0xdd, 0x70, 0x0a, 0x00, 0x00, + // 661 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x56, 0xcd, 0x6e, 0xd3, 0x40, + 0x10, 0xce, 0xd2, 0x1f, 0x35, 0x93, 0xb6, 0xc0, 0x96, 0xa4, 0x21, 0x15, 0xa9, 0x59, 0x2e, 0x91, + 0x2a, 0x39, 0xa4, 0x95, 0xca, 0x81, 0x53, 0xdb, 0x20, 0x35, 0x42, 0x82, 0xc8, 0x54, 0x54, 0xad, + 0x84, 0x2c, 0xd7, 0xde, 0x92, 0x55, 0x5c, 0x6f, 0xb0, 0xd7, 0x96, 0xcc, 0x03, 0x70, 0x83, 0x33, + 0xef, 0xc0, 0x5b, 0x70, 0xe2, 0xc8, 0x91, 0x23, 0x2a, 0x2f, 0x82, 0x62, 0x3b, 0xc1, 0xeb, 0x9a, + 0x34, 0x54, 0x54, 0x70, 0xb3, 0x67, 0xe7, 0xfb, 0xfc, 0xcd, 0xec, 0xfc, 0x18, 0x2a, 0x21, 0x77, + 0xfb, 0x8c, 0x36, 0x83, 0x56, 0x33, 0x7e, 0x52, 0x07, 0x2e, 0x17, 0x1c, 0x17, 0x93, 0xb7, 0xa0, + 0x55, 0xbb, 0xfb, 0xcb, 0xc5, 0xa5, 0x1e, 0xf7, 0x5d, 0x93, 0x7a, 0xb1, 0x17, 0xd9, 0x86, 0xf2, + 0x8e, 0x29, 0x58, 0x60, 0x08, 0xba, 0x67, 0x33, 0xea, 0x08, 0x8d, 0xbe, 0xf1, 0xa9, 0x27, 0xf0, + 0x3d, 0x00, 0x33, 0x32, 0xe8, 0x7d, 0x1a, 0x56, 0x91, 0x82, 0x1a, 0x45, 0xad, 0x18, 0x5b, 0x9e, + 0xd2, 0x90, 0x1c, 0x40, 0x25, 0x8b, 0xf3, 0x06, 0xdc, 0xf1, 0xe8, 0x25, 0x40, 0xbc, 0x06, 0xc9, + 0x8b, 0xce, 0xac, 0xea, 0x0d, 0x05, 0x35, 0x16, 0xb5, 0x85, 0xd8, 0xd0, 0xb1, 0xc8, 0x36, 0xac, + 0xb6, 0xa9, 0x91, 0xab, 0x47, 0xc2, 0xa1, 0x0c, 0xee, 0x11, 0x54, 0x2f, 0xe2, 0x12, 0x3d, 0x13, + 0x81, 0x36, 0x94, 0x77, 0x84, 0x30, 0xcc, 0x5e, 0x9b, 0x9b, 0xfe, 0xd9, 0x94, 0x9f, 0xc3, 0xdb, + 0x50, 0x32, 0x7b, 0x86, 0xf3, 0x9a, 0xea, 0x03, 0xc3, 0xec, 0x47, 0x51, 0x94, 0x36, 0xcb, 0xea, + 0x38, 0xe1, 0xea, 0x5e, 0x74, 0xda, 0x35, 0xcc, 0xbe, 0x06, 0xe6, 0xf8, 0x99, 0x7c, 0x40, 0x50, + 0xc9, 0x7e, 0x6e, 0x0a, 0x95, 0x78, 0x1d, 0x4a, 0x56, 0x02, 0x18, 0x65, 0xad, 0xa8, 0xc1, 0xc8, + 0x74, 0x51, 0xd0, 0xcc, 0xb4, 0x82, 0x3e, 0x23, 0x28, 0xb7, 0xe9, 0x1f, 0xc7, 0x7f, 0x5d, 0x7a, + 0xf0, 0x16, 0x54, 0x5c, 0x7a, 0xc6, 0x03, 0xaa, 0xb3, 0x53, 0xdd, 0xe1, 0x42, 0x37, 0xa2, 0x6c, + 0x51, 0xab, 0x3a, 0xab, 0xa0, 0xc6, 0x82, 0xb6, 0x12, 0x9f, 0x76, 0x4e, 0x9f, 0x71, 0xb1, 0x93, + 0x1c, 0x11, 0x0e, 0x95, 0x6c, 0x0c, 0xd3, 0x95, 0xe2, 0x55, 0xaf, 0xf1, 0x00, 0xee, 0x1c, 0x1a, + 0xe2, 0x2f, 0xe7, 0x8c, 0x7c, 0x43, 0x50, 0xce, 0xd0, 0x26, 0x61, 0x1c, 0xc1, 0x32, 0x73, 0x98, + 0x60, 0x86, 0xcd, 0xde, 0x1a, 0x82, 0x71, 0x27, 0x22, 0x2f, 0x6d, 0x36, 0x53, 0x52, 0x73, 0x91, + 0x6a, 0x47, 0x82, 0xed, 0x17, 0xb4, 0x0c, 0x11, 0xde, 0x80, 0x39, 0x1a, 0x50, 0x47, 0x24, 0xc1, + 0xaf, 0xa4, 0x18, 0xdb, 0xdc, 0x7c, 0x32, 0x3c, 0xda, 0x2f, 0x68, 0xb1, 0x4f, 0xad, 0x09, 0xcb, + 0x32, 0x61, 0x2a, 0xc1, 0xcc, 0xf2, 0xaa, 0x48, 0x99, 0x69, 0x2c, 0x8e, 0x12, 0xdc, 0xb1, 0xbc, + 0xdd, 0x79, 0x98, 0x3d, 0xe1, 0x56, 0x48, 0xde, 0x23, 0x28, 0x6b, 0xd1, 0xcd, 0xfd, 0x17, 0x65, + 0x36, 0xac, 0x98, 0xac, 0x9c, 0xeb, 0xad, 0x98, 0x4f, 0x08, 0x2a, 0x5d, 0xdf, 0xeb, 0x75, 0x7d, + 0xdb, 0x8e, 0x5d, 0xbc, 0x7f, 0xdb, 0x68, 0x6b, 0x50, 0x1c, 0xf8, 0x5e, 0x4f, 0xe7, 0x8e, 0x1d, + 0x26, 0xbd, 0xb5, 0x30, 0x34, 0x3c, 0x77, 0xec, 0x90, 0x38, 0xb0, 0x7a, 0x41, 0xec, 0x34, 0x63, + 0xea, 0x8a, 0xd9, 0xd9, 0x7c, 0x37, 0x07, 0x4b, 0x47, 0x91, 0xd3, 0x0b, 0xea, 0x06, 0xcc, 0xa4, + 0xf8, 0x10, 0x96, 0xe5, 0xed, 0x82, 0x95, 0x14, 0x4d, 0xee, 0xc2, 0xaa, 0xdd, 0x9f, 0xe0, 0x11, + 0xab, 0x27, 0x05, 0xfc, 0x0a, 0x6e, 0x65, 0x17, 0x05, 0x26, 0xe9, 0xa2, 0xcf, 0xdf, 0x3e, 0xb5, + 0x07, 0x13, 0x7d, 0xc6, 0xf4, 0x43, 0xdd, 0xd2, 0x7c, 0x97, 0x75, 0xe7, 0x6d, 0x1a, 0x59, 0x77, + 0xee, 0x72, 0x88, 0x89, 0xe5, 0x19, 0x27, 0x11, 0xe7, 0x8e, 0x70, 0x89, 0x38, 0x7f, 0x40, 0xc6, + 0xc4, 0x72, 0x2b, 0x48, 0xc4, 0xb9, 0x4d, 0x2b, 0x11, 0xe7, 0xf7, 0x11, 0x29, 0xe0, 0x63, 0xb8, + 0x99, 0x29, 0x22, 0x9c, 0xc6, 0xe5, 0x77, 0x43, 0x8d, 0x4c, 0x72, 0x19, 0x73, 0xbf, 0x84, 0x25, + 0x69, 0xde, 0xe1, 0xf5, 0xdf, 0x4f, 0xc2, 0x98, 0x57, 0xb9, 0x6c, 0x54, 0x92, 0xc2, 0x43, 0xb4, + 0xbb, 0xf1, 0xe5, 0xbc, 0x8e, 0xbe, 0x9e, 0xd7, 0xd1, 0xf7, 0xf3, 0x3a, 0xfa, 0xf8, 0xa3, 0x5e, + 0x80, 0xdb, 0x16, 0x0d, 0x46, 0x50, 0x63, 0xc0, 0xd4, 0xa0, 0xd5, 0x45, 0xc7, 0xb3, 0xea, 0xe3, + 0xa0, 0x75, 0x32, 0x1f, 0xfd, 0x40, 0x6d, 0xfd, 0x0c, 0x00, 0x00, 0xff, 0xff, 0x78, 0xaa, 0xfe, + 0x50, 0x80, 0x09, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1079,7 +980,6 @@ const _ = grpc.SupportPackageIsVersion4 type YorkieServiceClient interface { ActivateClient(ctx context.Context, in *ActivateClientRequest, opts ...grpc.CallOption) (*ActivateClientResponse, error) DeactivateClient(ctx context.Context, in *DeactivateClientRequest, opts ...grpc.CallOption) (*DeactivateClientResponse, error) - UpdatePresence(ctx context.Context, in *UpdatePresenceRequest, opts ...grpc.CallOption) (*UpdatePresenceResponse, error) AttachDocument(ctx context.Context, in *AttachDocumentRequest, opts ...grpc.CallOption) (*AttachDocumentResponse, error) DetachDocument(ctx context.Context, in *DetachDocumentRequest, opts ...grpc.CallOption) (*DetachDocumentResponse, error) RemoveDocument(ctx context.Context, in *RemoveDocumentRequest, opts ...grpc.CallOption) (*RemoveDocumentResponse, error) @@ -1113,15 +1013,6 @@ func (c *yorkieServiceClient) DeactivateClient(ctx context.Context, in *Deactiva return out, nil } -func (c *yorkieServiceClient) UpdatePresence(ctx context.Context, in *UpdatePresenceRequest, opts ...grpc.CallOption) (*UpdatePresenceResponse, error) { - out := new(UpdatePresenceResponse) - err := c.cc.Invoke(ctx, "/yorkie.v1.YorkieService/UpdatePresence", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *yorkieServiceClient) AttachDocument(ctx context.Context, in *AttachDocumentRequest, opts ...grpc.CallOption) (*AttachDocumentResponse, error) { out := new(AttachDocumentResponse) err := c.cc.Invoke(ctx, "/yorkie.v1.YorkieService/AttachDocument", in, out, opts...) @@ -1194,7 +1085,6 @@ func (x *yorkieServiceWatchDocumentClient) Recv() (*WatchDocumentResponse, error type YorkieServiceServer interface { ActivateClient(context.Context, *ActivateClientRequest) (*ActivateClientResponse, error) DeactivateClient(context.Context, *DeactivateClientRequest) (*DeactivateClientResponse, error) - UpdatePresence(context.Context, *UpdatePresenceRequest) (*UpdatePresenceResponse, error) AttachDocument(context.Context, *AttachDocumentRequest) (*AttachDocumentResponse, error) DetachDocument(context.Context, *DetachDocumentRequest) (*DetachDocumentResponse, error) RemoveDocument(context.Context, *RemoveDocumentRequest) (*RemoveDocumentResponse, error) @@ -1212,9 +1102,6 @@ func (*UnimplementedYorkieServiceServer) ActivateClient(ctx context.Context, req func (*UnimplementedYorkieServiceServer) DeactivateClient(ctx context.Context, req *DeactivateClientRequest) (*DeactivateClientResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method DeactivateClient not implemented") } -func (*UnimplementedYorkieServiceServer) UpdatePresence(ctx context.Context, req *UpdatePresenceRequest) (*UpdatePresenceResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method UpdatePresence not implemented") -} func (*UnimplementedYorkieServiceServer) AttachDocument(ctx context.Context, req *AttachDocumentRequest) (*AttachDocumentResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method AttachDocument not implemented") } @@ -1271,24 +1158,6 @@ func _YorkieService_DeactivateClient_Handler(srv interface{}, ctx context.Contex return interceptor(ctx, in, info, handler) } -func _YorkieService_UpdatePresence_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(UpdatePresenceRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(YorkieServiceServer).UpdatePresence(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/yorkie.v1.YorkieService/UpdatePresence", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(YorkieServiceServer).UpdatePresence(ctx, req.(*UpdatePresenceRequest)) - } - return interceptor(ctx, in, info, handler) -} - func _YorkieService_AttachDocument_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(AttachDocumentRequest) if err := dec(in); err != nil { @@ -1394,10 +1263,6 @@ var _YorkieService_serviceDesc = grpc.ServiceDesc{ MethodName: "DeactivateClient", Handler: _YorkieService_DeactivateClient_Handler, }, - { - MethodName: "UpdatePresence", - Handler: _YorkieService_UpdatePresence_Handler, - }, { MethodName: "AttachDocument", Handler: _YorkieService_AttachDocument_Handler, @@ -1807,15 +1672,10 @@ func (m *WatchDocumentRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x12 } - if m.Client != nil { - { - size, err := m.Client.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintYorkie(dAtA, i, uint64(size)) - } + if len(m.ClientId) > 0 { + i -= len(m.ClientId) + copy(dAtA[i:], m.ClientId) + i = encodeVarintYorkie(dAtA, i, uint64(len(m.ClientId))) i-- dAtA[i] = 0xa } @@ -1924,16 +1784,11 @@ func (m *WatchDocumentResponse_Initialization) MarshalToSizedBuffer(dAtA []byte) i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } - if len(m.Peers) > 0 { - for iNdEx := len(m.Peers) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Peers[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintYorkie(dAtA, i, uint64(size)) - } + if len(m.ClientIds) > 0 { + for iNdEx := len(m.ClientIds) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.ClientIds[iNdEx]) + copy(dAtA[i:], m.ClientIds[iNdEx]) + i = encodeVarintYorkie(dAtA, i, uint64(len(m.ClientIds[iNdEx]))) i-- dAtA[i] = 0xa } @@ -2149,79 +2004,6 @@ func (m *PushPullChangesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } -func (m *UpdatePresenceRequest) 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 *UpdatePresenceRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *UpdatePresenceRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.XXX_unrecognized != nil { - i -= len(m.XXX_unrecognized) - copy(dAtA[i:], m.XXX_unrecognized) - } - if len(m.DocumentId) > 0 { - i -= len(m.DocumentId) - copy(dAtA[i:], m.DocumentId) - i = encodeVarintYorkie(dAtA, i, uint64(len(m.DocumentId))) - i-- - dAtA[i] = 0x12 - } - if m.Client != nil { - { - size, err := m.Client.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintYorkie(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *UpdatePresenceResponse) 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 *UpdatePresenceResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *UpdatePresenceResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.XXX_unrecognized != nil { - i -= len(m.XXX_unrecognized) - copy(dAtA[i:], m.XXX_unrecognized) - } - return len(dAtA) - i, nil -} - func encodeVarintYorkie(dAtA []byte, offset int, v uint64) int { offset -= sovYorkie(v) base := offset @@ -2398,8 +2180,8 @@ func (m *WatchDocumentRequest) Size() (n int) { } var l int _ = l - if m.Client != nil { - l = m.Client.Size() + l = len(m.ClientId) + if l > 0 { n += 1 + l + sovYorkie(uint64(l)) } l = len(m.DocumentId) @@ -2457,9 +2239,9 @@ func (m *WatchDocumentResponse_Initialization) Size() (n int) { } var l int _ = l - if len(m.Peers) > 0 { - for _, e := range m.Peers { - l = e.Size() + if len(m.ClientIds) > 0 { + for _, b := range m.ClientIds { + l = len(b) n += 1 + l + sovYorkie(uint64(l)) } } @@ -2560,38 +2342,6 @@ func (m *PushPullChangesResponse) Size() (n int) { return n } -func (m *UpdatePresenceRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Client != nil { - l = m.Client.Size() - n += 1 + l + sovYorkie(uint64(l)) - } - l = len(m.DocumentId) - if l > 0 { - n += 1 + l + sovYorkie(uint64(l)) - } - if m.XXX_unrecognized != nil { - n += len(m.XXX_unrecognized) - } - return n -} - -func (m *UpdatePresenceResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.XXX_unrecognized != nil { - n += len(m.XXX_unrecognized) - } - return n -} - func sovYorkie(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -3565,9 +3315,9 @@ func (m *WatchDocumentRequest) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Client", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ClientId", wireType) } - var msglen int + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowYorkie @@ -3577,26 +3327,24 @@ func (m *WatchDocumentRequest) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + if byteLen < 0 { return ErrInvalidLengthYorkie } - postIndex := iNdEx + msglen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthYorkie } if postIndex > l { return io.ErrUnexpectedEOF } - if m.Client == nil { - m.Client = &Client{} - } - if err := m.Client.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err + m.ClientId = append(m.ClientId[:0], dAtA[iNdEx:postIndex]...) + if m.ClientId == nil { + m.ClientId = []byte{} } iNdEx = postIndex case 2: @@ -3805,9 +3553,9 @@ func (m *WatchDocumentResponse_Initialization) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Peers", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ClientIds", wireType) } - var msglen int + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowYorkie @@ -3817,25 +3565,23 @@ func (m *WatchDocumentResponse_Initialization) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + if byteLen < 0 { return ErrInvalidLengthYorkie } - postIndex := iNdEx + msglen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthYorkie } if postIndex > l { return io.ErrUnexpectedEOF } - m.Peers = append(m.Peers, &Client{}) - if err := m.Peers[len(m.Peers)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.ClientIds = append(m.ClientIds, make([]byte, postIndex-iNdEx)) + copy(m.ClientIds[len(m.ClientIds)-1], dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -4425,176 +4171,6 @@ func (m *PushPullChangesResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *UpdatePresenceRequest) 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 ErrIntOverflowYorkie - } - 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: UpdatePresenceRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: UpdatePresenceRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Client", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowYorkie - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthYorkie - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthYorkie - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Client == nil { - m.Client = &Client{} - } - if err := m.Client.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DocumentId", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowYorkie - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthYorkie - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthYorkie - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.DocumentId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipYorkie(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthYorkie - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *UpdatePresenceResponse) 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 ErrIntOverflowYorkie - } - 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: UpdatePresenceResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: UpdatePresenceResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - default: - iNdEx = preIndex - skippy, err := skipYorkie(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthYorkie - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func skipYorkie(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/api/yorkie/v1/yorkie.proto b/api/yorkie/v1/yorkie.proto index 0acf21d99..b4f0eda6a 100644 --- a/api/yorkie/v1/yorkie.proto +++ b/api/yorkie/v1/yorkie.proto @@ -28,7 +28,6 @@ option java_package = "dev.yorkie.api.v1"; service YorkieService { rpc ActivateClient (ActivateClientRequest) returns (ActivateClientResponse) {} rpc DeactivateClient (DeactivateClientRequest) returns (DeactivateClientResponse) {} - rpc UpdatePresence (UpdatePresenceRequest) returns (UpdatePresenceResponse) {} rpc AttachDocument (AttachDocumentRequest) returns (AttachDocumentResponse) {} rpc DetachDocument (DetachDocumentRequest) returns (DetachDocumentResponse) {} @@ -79,13 +78,13 @@ message DetachDocumentResponse { } message WatchDocumentRequest { - Client client = 1; + bytes client_id = 1; string document_id = 2; } message WatchDocumentResponse { message Initialization { - repeated Client peers = 1; + repeated bytes client_ids = 1; } oneof body { @@ -116,10 +115,3 @@ message PushPullChangesResponse { bytes client_id = 1; ChangePack change_pack = 2; } - -message UpdatePresenceRequest { - Client client = 1; - string document_id = 2; -} - -message UpdatePresenceResponse {} diff --git a/client/client.go b/client/client.go index d8d952342..655433967 100644 --- a/client/client.go +++ b/client/client.go @@ -24,19 +24,21 @@ import ( "fmt" "strings" - "google.golang.org/grpc/metadata" - "github.com/rs/xid" "go.uber.org/zap" "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/metadata" "github.com/yorkie-team/yorkie/api/converter" "github.com/yorkie-team/yorkie/api/types" api "github.com/yorkie-team/yorkie/api/yorkie/v1" "github.com/yorkie-team/yorkie/pkg/document" + "github.com/yorkie-team/yorkie/pkg/document/innerpresence" + "github.com/yorkie-team/yorkie/pkg/document/json" "github.com/yorkie-team/yorkie/pkg/document/key" + "github.com/yorkie-team/yorkie/pkg/document/presence" "github.com/yorkie-team/yorkie/pkg/document/time" ) @@ -65,26 +67,10 @@ var ( ErrUnsupportedWatchResponseType = errors.New("unsupported watch response type") ) -// SyncOption is an option for sync. It contains the key of the document to -// sync and the sync mode. -type SyncOption struct { - key key.Key - mode types.SyncMode -} - -// WithPushOnly returns a SyncOption with the sync mode set to PushOnly. -func (o SyncOption) WithPushOnly() SyncOption { - return SyncOption{ - key: o.key, - mode: types.SyncModePushOnly, - } -} - -// Attachment represents the document attached and peers. +// Attachment represents the document attached. type Attachment struct { doc *document.Document docID types.ID - peers map[string]types.PresenceInfo } // Client is a normal client that can communicate with the server. @@ -97,11 +83,10 @@ type Client struct { dialOptions []grpc.DialOption logger *zap.Logger - id *time.ActorID - key string - presenceInfo types.PresenceInfo - status status - attachments map[key.Key]*Attachment + id *time.ActorID + key string + status status + attachments map[key.Key]*Attachment } // WatchResponseType is type of watch response. @@ -109,16 +94,17 @@ type WatchResponseType string // The values below are types of WatchResponseType. const ( - DocumentsChanged WatchResponseType = "documents-changed" - PeersChanged WatchResponseType = "peers-changed" + DocumentChanged WatchResponseType = "document-changed" + DocumentWatched WatchResponseType = "document-watched" + DocumentUnwatched WatchResponseType = "document-unwatched" + PresenceChanged WatchResponseType = "presence-changed" ) // WatchResponse is a structure representing response of Watch. type WatchResponse struct { - Type WatchResponseType - Key key.Key - PeersMapByDoc map[key.Key]map[string]types.Presence - Err error + Type WatchResponseType + Presences map[string]innerpresence.Presence + Err error } // New creates an instance of Client. @@ -133,11 +119,6 @@ func New(opts ...Option) (*Client, error) { k = xid.New().String() } - presence := types.Presence{} - if options.Presence != nil { - presence = options.Presence - } - var dialOptions []grpc.DialOption transportCreds := grpc.WithTransportCredentials(insecure.NewCredentials()) @@ -172,10 +153,9 @@ func New(opts ...Option) (*Client, error) { options: options, logger: logger, - key: k, - presenceInfo: types.PresenceInfo{Presence: presence}, - status: deactivated, - attachments: make(map[key.Key]*Attachment), + key: k, + status: deactivated, + attachments: make(map[key.Key]*Attachment), }, nil } @@ -265,7 +245,7 @@ func (c *Client) Deactivate(ctx context.Context) error { // Attach attaches the given document to this client. It tells the server that // this client will synchronize the given document. -func (c *Client) Attach(ctx context.Context, doc *document.Document) error { +func (c *Client) Attach(ctx context.Context, doc *document.Document, options ...AttachOption) error { if c.status != activated { return ErrClientNotActivated } @@ -274,8 +254,20 @@ func (c *Client) Attach(ctx context.Context, doc *document.Document) error { return ErrDocumentNotDetached } + opts := &AttachOptions{} + for _, opt := range options { + opt(opts) + } + doc.SetActor(c.id) + if err := doc.Update(func(root *json.Object, p *presence.Presence) error { + p.Initialize(opts.Presence) + return nil + }); err != nil { + return err + } + pbChangePack, err := converter.ToChangePack(doc.CreateChangePack()) if err != nil { return err @@ -316,7 +308,6 @@ func (c *Client) Attach(ctx context.Context, doc *document.Document) error { c.attachments[doc.Key()] = &Attachment{ doc: doc, docID: types.ID(res.DocumentId), - peers: make(map[string]types.PresenceInfo), } return nil @@ -328,16 +319,28 @@ func (c *Client) Attach(ctx context.Context, doc *document.Document) error { // To collect garbage things like CRDT tombstones left on the document, all the // changes should be applied to other replicas before GC time. For this, if the // document is no longer used by this client, it should be detached. -func (c *Client) Detach(ctx context.Context, doc *document.Document, removeIfNotAttached bool) error { +func (c *Client) Detach(ctx context.Context, doc *document.Document, options ...DetachOption) error { if c.status != activated { return ErrClientNotActivated } + opts := &DetachOptions{} + for _, opt := range options { + opt(opts) + } + attachment, ok := c.attachments[doc.Key()] if !ok { return ErrDocumentNotAttached } + if err := doc.Update(func(root *json.Object, p *presence.Presence) error { + p.Clear() + return nil + }); err != nil { + return err + } + pbChangePack, err := converter.ToChangePack(doc.CreateChangePack()) if err != nil { return err @@ -349,7 +352,7 @@ func (c *Client) Detach(ctx context.Context, doc *document.Document, removeIfNot ClientId: c.id.Bytes(), DocumentId: attachment.docID.String(), ChangePack: pbChangePack, - RemoveIfNotAttached: removeIfNotAttached, + RemoveIfNotAttached: opts.removeIfNotAttached, }, ) if err != nil { @@ -372,18 +375,10 @@ func (c *Client) Detach(ctx context.Context, doc *document.Document, removeIfNot return nil } -// WithDocKey creates a SyncOption with the given document key. -func WithDocKey(k key.Key) SyncOption { - return SyncOption{ - key: k, - mode: types.SyncModePushPull, - } -} - // Sync pushes local changes of the attached documents to the server and // receives changes of the remote replica from the server then apply them to // local documents. -func (c *Client) Sync(ctx context.Context, options ...SyncOption) error { +func (c *Client) Sync(ctx context.Context, options ...SyncOptions) error { if len(options) == 0 { for _, attachment := range c.attachments { options = append(options, WithDocKey(attachment.doc.Key())) @@ -417,10 +412,7 @@ func (c *Client) Watch( stream, err := c.client.WatchDocument( withShardKey(ctx, c.options.APIKey, doc.Key().String()), &api.WatchDocumentRequest{ - Client: converter.ToClient(types.Client{ - ID: c.id, - PresenceInfo: c.presenceInfo, - }), + ClientId: c.id.Bytes(), DocumentId: attachment.docID.String(), }, ) @@ -431,16 +423,16 @@ func (c *Client) Watch( handleResponse := func(pbResp *api.WatchDocumentResponse) (*WatchResponse, error) { switch resp := pbResp.Body.(type) { case *api.WatchDocumentResponse_Initialization_: - clients, err := converter.FromClients(resp.Initialization.Peers) - if err != nil { - return nil, err - } - - attachment := c.attachments[doc.Key()] - for _, cli := range clients { - attachment.peers[cli.ID.String()] = cli.PresenceInfo + var clientIDs []string + for _, clientID := range resp.Initialization.ClientIds { + id, err := time.ActorIDFromBytes(clientID) + if err != nil { + return nil, err + } + clientIDs = append(clientIDs, id.String()) } + doc.SetOnlineClientSet(clientIDs...) return nil, nil case *api.WatchDocumentResponse_Event: eventType, err := converter.FromEventType(resp.Event.Type) @@ -448,37 +440,35 @@ func (c *Client) Watch( return nil, err } - docKey, err := c.findDocKey(resp.Event.DocumentId) + cli, err := time.ActorIDFromBytes(resp.Event.Publisher) if err != nil { return nil, err } switch eventType { case types.DocumentsChangedEvent: - return &WatchResponse{ - Type: DocumentsChanged, - Key: docKey, - }, nil - case types.DocumentsWatchedEvent, types.DocumentsUnwatchedEvent, types.PresenceChangedEvent: - cli, err := converter.FromClient(resp.Event.Publisher) - if err != nil { - return nil, err + return &WatchResponse{Type: DocumentChanged}, nil + case types.DocumentsWatchedEvent: + doc.AddOnlineClient(cli.String()) + if doc.OnlinePresence(cli.String()) == nil { + return nil, nil } - attachment := c.attachments[docKey] - if eventType == types.DocumentsWatchedEvent || - eventType == types.PresenceChangedEvent { - if info, ok := attachment.peers[cli.ID.String()]; ok { - cli.PresenceInfo.Update(info) - } - attachment.peers[cli.ID.String()] = cli.PresenceInfo - } else { - delete(attachment.peers, cli.ID.String()) - } + return &WatchResponse{ + Type: DocumentWatched, + Presences: map[string]innerpresence.Presence{ + cli.String(): doc.OnlinePresence(cli.String()), + }, + }, nil + case types.DocumentsUnwatchedEvent: + p := doc.OnlinePresence(cli.String()) + doc.RemoveOnlineClient(cli.String()) return &WatchResponse{ - Type: PeersChanged, - PeersMapByDoc: c.PeersMapByDoc(), + Type: DocumentUnwatched, + Presences: map[string]innerpresence.Presence{ + cli.String(): p, + }, }, nil } } @@ -507,10 +497,38 @@ func (c *Client) Watch( close(rch) return } + if resp == nil { + continue + } + rch <- *resp } }() + // TODO(hackerwins): We need to revise the implementation of the watch + // event handling. Currently, we are using the same channel for both + // document events and watch events. This is not ideal because the + // client cannot distinguish between document events and watch events. + // We'll expose only document events and watch events will be handled + // internally. + + // TODO(hackerwins): We should ensure that the goroutine is closed when + // the stream is closed. + go func() { + for { + select { + case e := <-doc.Events(): + t := PresenceChanged + if e.Type == document.WatchedEvent { + t = DocumentWatched + } + rch <- WatchResponse{Type: t, Presences: e.Presences} + case <-ctx.Done(): + return + } + } + }() + return rch, nil } @@ -524,41 +542,6 @@ func (c *Client) findDocKey(docID string) (key.Key, error) { return "", ErrDocumentNotAttached } -// UpdatePresence updates the presence of this client. -func (c *Client) UpdatePresence(ctx context.Context, k, v string) error { - if c.status != activated { - return ErrClientNotActivated - } - - c.presenceInfo.Presence[k] = v - c.presenceInfo.Clock++ - - if len(c.attachments) == 0 { - return nil - } - - // TODO(hackerwins): We temporarily use Unary Call to update presence, - // because grpc-web can't handle Bi-Directional streaming for now. - // After grpc-web supports bi-directional streaming, we can remove the - // following. - // TODO(hackerwins): We will move Presence from client-level to document-level. - for _, attachment := range c.attachments { - if _, err := c.client.UpdatePresence( - withShardKey(ctx, c.options.APIKey, attachment.doc.Key().String()), - &api.UpdatePresenceRequest{ - Client: converter.ToClient(types.Client{ - ID: c.id, - PresenceInfo: c.presenceInfo, - }), - DocumentId: attachment.docID.String(), - }); err != nil { - return err - } - } - - return nil -} - // ID returns the ID of this client. func (c *Client) ID() *time.ActorID { return c.id @@ -569,36 +552,13 @@ func (c *Client) Key() string { return c.key } -// Presence returns the presence data of this client. -func (c *Client) Presence() types.Presence { - presence := make(types.Presence) - for k, v := range c.presenceInfo.Presence { - presence[k] = v - } - - return presence -} - -// PeersMapByDoc returns the peersMap. -func (c *Client) PeersMapByDoc() map[key.Key]map[string]types.Presence { - peersMapByDoc := make(map[key.Key]map[string]types.Presence) - for docKey, attachment := range c.attachments { - peers := make(map[string]types.Presence) - for id, info := range attachment.peers { - peers[id] = info.Presence - } - peersMapByDoc[docKey] = peers - } - return peersMapByDoc -} - // IsActive returns whether this client is active or not. func (c *Client) IsActive() bool { return c.status == activated } // pushPullChanges pushes the changes of the document to the server and pulls the changes from the server. -func (c *Client) pushPullChanges(ctx context.Context, opt SyncOption) error { +func (c *Client) pushPullChanges(ctx context.Context, opt SyncOptions) error { if c.status != activated { return ErrClientNotActivated } diff --git a/client/client_test.go b/client/client_test.go index 0b1539af0..e7a32877b 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -78,13 +78,10 @@ func (s *testYorkieServer) Stop() { func TestClient(t *testing.T) { t.Run("create instance test", func(t *testing.T) { - presence := types.Presence{"Name": "ClientName"} - cli, err := client.New( + _, err := client.New( client.WithToken(xid.New().String()), - client.WithPresence(presence), ) assert.NoError(t, err) - assert.Equal(t, presence, cli.Presence()) }) t.Run("x-shard-key test", func(t *testing.T) { diff --git a/client/options.go b/client/options.go index ba84db28b..82c50f1a3 100644 --- a/client/options.go +++ b/client/options.go @@ -20,6 +20,8 @@ import ( "go.uber.org/zap" "github.com/yorkie-team/yorkie/api/types" + "github.com/yorkie-team/yorkie/pkg/document/innerpresence" + "github.com/yorkie-team/yorkie/pkg/document/key" ) // Option configures Options. @@ -30,9 +32,6 @@ type Options struct { // Key is the key of the client. It is used to identify the client. Key string - // Presence is the presence of the client. - Presence types.Presence - // APIKey is the API key of the client. APIKey string @@ -57,11 +56,6 @@ func WithKey(key string) Option { return func(o *Options) { o.Key = key } } -// WithPresence configures the presence of the client. -func WithPresence(presence types.Presence) Option { - return func(o *Options) { o.Presence = presence } -} - // WithAPIKey configures the API key of the client. func WithAPIKey(apiKey string) Option { return func(o *Options) { o.APIKey = apiKey } @@ -91,3 +85,53 @@ func WithLogger(logger *zap.Logger) Option { func WithMaxRecvMsgSize(maxRecvMsgSize int) Option { return func(o *Options) { o.MaxCallRecvMsgSize = maxRecvMsgSize } } + +// AttachOption configures AttachOptions. +type AttachOption func(*AttachOptions) + +// AttachOptions configures how we set up the document. +type AttachOptions struct { + // Presence is the presence of the client. + Presence innerpresence.Presence +} + +// WithPresence configures the presence of the client. +func WithPresence(presence innerpresence.Presence) AttachOption { + return func(o *AttachOptions) { o.Presence = presence } +} + +// DetachOption configures DetachOptions. +type DetachOption func(*DetachOptions) + +// DetachOptions configures how we set up the document. +type DetachOptions struct { + removeIfNotAttached bool +} + +// WithRemoveIfNotAttached configures the removeIfNotAttached of the document. +func WithRemoveIfNotAttached() DetachOption { + return func(o *DetachOptions) { o.removeIfNotAttached = true } +} + +// SyncOptions is an option for sync. It contains the key of the document to +// sync and the sync mode. +type SyncOptions struct { + key key.Key + mode types.SyncMode +} + +// WithDocKey creates a SyncOptions with the given document key. +func WithDocKey(k key.Key) SyncOptions { + return SyncOptions{ + key: k, + mode: types.SyncModePushPull, + } +} + +// WithPushOnly returns a SyncOptions with the sync mode set to PushOnly. +func (o SyncOptions) WithPushOnly() SyncOptions { + return SyncOptions{ + key: o.key, + mode: types.SyncModePushOnly, + } +} diff --git a/pkg/document/change/change.go b/pkg/document/change/change.go index ed392207f..88a638ba1 100644 --- a/pkg/document/change/change.go +++ b/pkg/document/change/change.go @@ -20,6 +20,7 @@ package change import ( "github.com/yorkie-team/yorkie/pkg/document/crdt" + "github.com/yorkie-team/yorkie/pkg/document/innerpresence" "github.com/yorkie-team/yorkie/pkg/document/operations" "github.com/yorkie-team/yorkie/pkg/document/time" ) @@ -34,24 +35,38 @@ type Change struct { // operations represent a series of user edits. operations []operations.Operation + + // presenceChange represents the presenceChange of the user who made the change. + // TODO(hackerwins): Consider using changes instead of entire presenceChange. + presenceChange *innerpresence.PresenceChange } // New creates a new instance of Change. -func New(id ID, message string, operations []operations.Operation) *Change { +func New(id ID, message string, operations []operations.Operation, p *innerpresence.PresenceChange) *Change { return &Change{ - id: id, - message: message, - operations: operations, + id: id, + message: message, + operations: operations, + presenceChange: p, } } // Execute applies this change to the given JSON root. -func (c *Change) Execute(root *crdt.Root) error { +func (c *Change) Execute(root *crdt.Root, presences *innerpresence.Map) error { for _, op := range c.operations { if err := op.Execute(root); err != nil { return err } } + + if c.presenceChange != nil { + if c.presenceChange.ChangeType == innerpresence.Clear { + presences.Delete(c.id.actorID.String()) + } else { + presences.Store(c.id.actorID.String(), c.presenceChange.Presence) + } + } + return nil } @@ -92,3 +107,8 @@ func (c *Change) SetActor(actor *time.ActorID) { op.SetActor(actor) } } + +// PresenceChange returns the presence change of this change. +func (c *Change) PresenceChange() *innerpresence.PresenceChange { + return c.presenceChange +} diff --git a/pkg/document/change/checkpoint.go b/pkg/document/change/checkpoint.go index 0be20a7ed..8967b9c43 100644 --- a/pkg/document/change/checkpoint.go +++ b/pkg/document/change/checkpoint.go @@ -115,7 +115,7 @@ func (cp Checkpoint) Forward(other Checkpoint) Checkpoint { } // Equals returns whether the given checkpoint is equal to this checkpoint or not. -func (cp *Checkpoint) Equals(other Checkpoint) bool { +func (cp Checkpoint) Equals(other Checkpoint) bool { return cp.ServerSeq == other.ServerSeq && cp.ClientSeq == other.ClientSeq } diff --git a/pkg/document/change/context.go b/pkg/document/change/context.go index 931d7859e..c494644fb 100644 --- a/pkg/document/change/context.go +++ b/pkg/document/change/context.go @@ -18,6 +18,7 @@ package change import ( "github.com/yorkie-team/yorkie/pkg/document/crdt" + "github.com/yorkie-team/yorkie/pkg/document/innerpresence" "github.com/yorkie-team/yorkie/pkg/document/operations" "github.com/yorkie-team/yorkie/pkg/document/time" ) @@ -26,11 +27,12 @@ import ( // Each time we add an operation, a new time ticket is issued. // Finally, returns a Change after the modification has been completed. type Context struct { - id ID - message string - operations []operations.Operation - delimiter uint32 - root *crdt.Root + id ID + message string + operations []operations.Operation + delimiter uint32 + root *crdt.Root + presenceChange *innerpresence.PresenceChange } // NewContext creates a new instance of Context. @@ -49,12 +51,12 @@ func (c *Context) ID() ID { // ToChange creates a new change of this context. func (c *Context) ToChange() *Change { - return New(c.id, c.message, c.operations) + return New(c.id, c.message, c.operations, c.presenceChange) } -// HasOperations returns whether this change has operations or not. -func (c *Context) HasOperations() bool { - return len(c.operations) > 0 +// HasChange returns whether this context has changes. +func (c *Context) HasChange() bool { + return len(c.operations) > 0 || c.presenceChange != nil } // IssueTimeTicket creates a time ticket to be used to create a new operation. @@ -87,3 +89,8 @@ func (c *Context) RegisterElementHasRemovedNodes(element crdt.GCElement) { func (c *Context) LastTimeTicket() *time.Ticket { return c.id.NewTimeTicket(c.delimiter) } + +// SetPresenceChange sets the presence change of the user who made the change. +func (c *Context) SetPresenceChange(presenceChange innerpresence.PresenceChange) { + c.presenceChange = &presenceChange +} diff --git a/pkg/document/document.go b/pkg/document/document.go index 5c98d5b07..985dd2f6d 100644 --- a/pkg/document/document.go +++ b/pkg/document/document.go @@ -22,11 +22,32 @@ import ( "github.com/yorkie-team/yorkie/pkg/document/change" "github.com/yorkie-team/yorkie/pkg/document/crdt" + "github.com/yorkie-team/yorkie/pkg/document/innerpresence" "github.com/yorkie-team/yorkie/pkg/document/json" "github.com/yorkie-team/yorkie/pkg/document/key" + "github.com/yorkie-team/yorkie/pkg/document/presence" "github.com/yorkie-team/yorkie/pkg/document/time" ) +// DocEvent represents the event that occurred in the document. +type DocEvent struct { + Type DocEventType + Presences map[string]innerpresence.Presence +} + +// DocEventType represents the type of the event that occurred in the document. +type DocEventType string + +const ( + // WatchedEvent means that the client has established a connection with the server, + // enabling real-time synchronization. + WatchedEvent DocEventType = "watched" + + // PresenceChangedEvent means that the presences of the clients who are editing + // the document have changed. + PresenceChangedEvent DocEventType = "presence-changed" +) + // Document represents a document accessible to the user. // // How document works: @@ -38,21 +59,29 @@ type Document struct { // doc is the original data of the actual document. doc *InternalDocument - // clone is a copy of `doc` to be exposed to the user and is used to - // protect `doc`. - clone *crdt.Root + // cloneRoot is a copy of `doc.root` to be exposed to the user and is used to + // protect `doc.root`. + cloneRoot *crdt.Root + + // clonePresences is a copy of `doc.presences` to be exposed to the user and + // is used to protect `doc.presences`. + clonePresences *innerpresence.Map + + // events is the channel to send events that occurred in the document. + events chan DocEvent } // New creates a new instance of Document. func New(key key.Key) *Document { return &Document{ - doc: NewInternalDocument(key), + doc: NewInternalDocument(key), + events: make(chan DocEvent, 1), } } // Update executes the given updater to update this document. func (d *Document) Update( - updater func(root *json.Object) error, + updater func(root *json.Object, p *presence.Presence) error, msgAndArgs ...interface{}, ) error { if d.doc.status == StatusRemoved { @@ -66,18 +95,22 @@ func (d *Document) Update( ctx := change.NewContext( d.doc.changeID.Next(), messageFromMsgAndArgs(msgAndArgs...), - d.clone, + d.cloneRoot, ) - if err := updater(json.NewObject(ctx, d.clone.Object())); err != nil { - // drop clone because it is contaminated. - d.clone = nil + if err := updater( + json.NewObject(ctx, d.cloneRoot.Object()), + presence.New(ctx, d.clonePresences.LoadOrStore(d.ActorID().String(), innerpresence.NewPresence())), + ); err != nil { + // drop cloneRoot because it is contaminated. + d.cloneRoot = nil + d.clonePresences = nil return err } - if ctx.HasOperations() { + if ctx.HasChange() { c := ctx.ToChange() - if err := c.Execute(d.doc.root); err != nil { + if err := c.Execute(d.doc.root, d.doc.presences); err != nil { return err } @@ -90,9 +123,10 @@ func (d *Document) Update( // ApplyChangePack applies the given change pack into this document. func (d *Document) ApplyChangePack(pack *change.Pack) error { - // 01. Apply remote changes to both the clone and the document. + // 01. Apply remote changes to both the cloneRoot and the document. if len(pack.Snapshot) > 0 { - d.clone = nil + d.cloneRoot = nil + d.clonePresences = nil if err := d.doc.applySnapshot(pack.Snapshot, pack.Checkpoint.ServerSeq); err != nil { return err } @@ -102,14 +136,19 @@ func (d *Document) ApplyChangePack(pack *change.Pack) error { } for _, c := range pack.Changes { - if err := c.Execute(d.clone); err != nil { + if err := c.Execute(d.cloneRoot, d.clonePresences); err != nil { return err } } - if err := d.doc.ApplyChanges(pack.Changes...); err != nil { + events, err := d.doc.ApplyChanges(pack.Changes...) + if err != nil { return err } + + for _, e := range events { + d.events <- e + } } // 02. Remove local changes applied to server. @@ -186,7 +225,7 @@ func (d *Document) Status() StatusType { return d.doc.status } -// IsAttached returns the whether this document is attached or not. +// IsAttached returns whether this document is attached or not. func (d *Document) IsAttached() bool { return d.doc.IsAttached() } @@ -202,14 +241,14 @@ func (d *Document) Root() *json.Object { panic(err) } - ctx := change.NewContext(d.doc.changeID.Next(), "", d.clone) - return json.NewObject(ctx, d.clone.Object()) + ctx := change.NewContext(d.doc.changeID.Next(), "", d.cloneRoot) + return json.NewObject(ctx, d.cloneRoot.Object()) } // GarbageCollect purge elements that were removed before the given time. func (d *Document) GarbageCollect(ticket *time.Ticket) int { - if d.clone != nil { - if _, err := d.clone.GarbageCollect(ticket); err != nil { + if d.cloneRoot != nil { + if _, err := d.cloneRoot.GarbageCollect(ticket); err != nil { panic(err) } } @@ -228,16 +267,68 @@ func (d *Document) GarbageLen() int { } func (d *Document) ensureClone() error { - if d.clone == nil { + if d.cloneRoot == nil { copiedDoc, err := d.doc.root.DeepCopy() if err != nil { return err } - d.clone = copiedDoc + d.cloneRoot = copiedDoc } + + if d.clonePresences == nil { + d.clonePresences = d.doc.presences.DeepCopy() + } + return nil } +// Presences returns the presence map of this document. +func (d *Document) Presences() map[string]innerpresence.Presence { + // TODO(hackerwins): We need to use client key instead of actor ID for exposing presence. + presences := make(map[string]innerpresence.Presence) + d.doc.presences.Range(func(key string, value innerpresence.Presence) bool { + presences[key] = value + return true + }) + return presences +} + +// Presence returns the presence of the given client. +func (d *Document) Presence(clientID string) innerpresence.Presence { + return d.doc.Presence(clientID) +} + +// MyPresence returns the presence of the actor. +func (d *Document) MyPresence() innerpresence.Presence { + return d.doc.MyPresence() +} + +// SetOnlineClientSet sets the online client set. +func (d *Document) SetOnlineClientSet(clientIDs ...string) { + d.doc.SetOnlineClientSet(clientIDs...) +} + +// AddOnlineClient adds the given client to the online client set. +func (d *Document) AddOnlineClient(clientID string) { + d.doc.AddOnlineClient(clientID) +} + +// RemoveOnlineClient removes the given client from the online client set. +func (d *Document) RemoveOnlineClient(clientID string) { + d.doc.RemoveOnlineClient(clientID) +} + +// OnlinePresence returns the presence of the given client. If the client is not +// online, it returns nil. +func (d *Document) OnlinePresence(clientID string) innerpresence.Presence { + return d.doc.OnlinePresence(clientID) +} + +// Events returns the events of this document. +func (d *Document) Events() <-chan DocEvent { + return d.events +} + func messageFromMsgAndArgs(msgAndArgs ...interface{}) string { if len(msgAndArgs) == 0 { return "" diff --git a/pkg/document/document_test.go b/pkg/document/document_test.go index b4a221a31..dd3e62673 100644 --- a/pkg/document/document_test.go +++ b/pkg/document/document_test.go @@ -27,6 +27,7 @@ import ( "github.com/yorkie-team/yorkie/pkg/document/change" "github.com/yorkie-team/yorkie/pkg/document/crdt" "github.com/yorkie-team/yorkie/pkg/document/json" + "github.com/yorkie-team/yorkie/pkg/document/presence" "github.com/yorkie-team/yorkie/pkg/document/time" ) @@ -54,7 +55,7 @@ func TestDocument(t *testing.T) { doc2 := document.New("d2") doc3 := document.New("d3") - err := doc1.Update(func(root *json.Object) error { + err := doc1.Update(func(root *json.Object, p *presence.Presence) error { root.SetString("k1", "v1") return nil }, "updates k1") @@ -71,7 +72,7 @@ func TestDocument(t *testing.T) { assert.Equal(t, "{}", doc.Marshal()) assert.False(t, doc.HasLocalChanges()) - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetString("k1", "v1") root.SetNewObject("k2").SetString("k4", "v4") root.SetNewArray("k3").AddString("v5", "v6") @@ -89,7 +90,7 @@ func TestDocument(t *testing.T) { assert.Equal(t, "{}", doc.Marshal()) assert.False(t, doc.HasLocalChanges()) expected := `{"k1":"v1","k2":{"k4":"v4"},"k3":["v5","v6"]}` - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetString("k1", "v1") root.SetNewObject("k2").SetString("k4", "v4") root.SetNewArray("k3").AddString("v5", "v6") @@ -100,7 +101,7 @@ func TestDocument(t *testing.T) { assert.Equal(t, expected, doc.Marshal()) expected = `{"k1":"v1","k3":["v5","v6"]}` - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { root.Delete("k2") assert.Equal(t, expected, root.Marshal()) return nil @@ -111,7 +112,7 @@ func TestDocument(t *testing.T) { t.Run("object test", func(t *testing.T) { doc := document.New("d1") - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetString("k1", "v1") assert.Equal(t, `{"k1":"v1"}`, root.Marshal()) root.SetString("k1", "v2") @@ -125,7 +126,7 @@ func TestDocument(t *testing.T) { t.Run("array test", func(t *testing.T) { doc := document.New("d1") - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewArray("k1").AddInteger(1).AddInteger(2).AddInteger(3) assert.Equal(t, 3, root.GetArray("k1").Len()) assert.Equal(t, `{"k1":[1,2,3]}`, root.Marshal()) @@ -162,7 +163,7 @@ func TestDocument(t *testing.T) { t.Run("delete elements of array test", func(t *testing.T) { doc := document.New("d1") - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewArray("data").AddInteger(0).AddInteger(1).AddInteger(2) return nil }) @@ -170,7 +171,7 @@ func TestDocument(t *testing.T) { assert.Equal(t, `{"data":[0,1,2]}`, doc.Marshal()) assert.Equal(t, 3, doc.Root().GetArray("data").Len()) - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { root.GetArray("data").Delete(0) return nil }) @@ -178,7 +179,7 @@ func TestDocument(t *testing.T) { assert.Equal(t, `{"data":[1,2]}`, doc.Marshal()) assert.Equal(t, 2, doc.Root().GetArray("data").Len()) - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { root.GetArray("data").Delete(1) return nil }) @@ -186,7 +187,7 @@ func TestDocument(t *testing.T) { assert.Equal(t, `{"data":[1]}`, doc.Marshal()) assert.Equal(t, 1, doc.Root().GetArray("data").Len()) - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { root.GetArray("data").Delete(0) return nil }) @@ -201,7 +202,7 @@ func TestDocument(t *testing.T) { // ---------- ins links -------- // | | | // [init] - [A] - [12] - [BC deleted] - [D] - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewText("k1"). Edit(0, 0, "ABCD"). Edit(1, 3, "12") @@ -211,7 +212,7 @@ func TestDocument(t *testing.T) { assert.NoError(t, err) assert.Equal(t, `{"k1":[{"val":"A"},{"val":"12"},{"val":"D"}]}`, doc.Marshal()) - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { text := root.GetText("k1") assert.Equal(t, `[0:0:00:0 {} ""][1:2:00:0 {} "A"][1:3:00:0 {} "12"]{1:2:00:1 {} "BC"}[1:2:00:3 {} "D"]`, @@ -240,7 +241,7 @@ func TestDocument(t *testing.T) { t.Run("text composition test", func(t *testing.T) { doc := document.New("d1") - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewText("k1"). Edit(0, 0, "ㅎ"). Edit(0, 1, "하"). @@ -258,7 +259,7 @@ func TestDocument(t *testing.T) { t.Run("rich text test", func(t *testing.T) { doc := document.New("d1") - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { text := root.SetNewText("k1") text.Edit(0, 0, "Hello world", nil) assert.Equal( @@ -271,7 +272,7 @@ func TestDocument(t *testing.T) { assert.NoError(t, err) assert.Equal(t, `{"k1":[{"val":"Hello world"}]}`, doc.Marshal()) - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { text := root.GetText("k1") text.Style(0, 5, map[string]string{"b": "1"}) assert.Equal(t, @@ -287,7 +288,7 @@ func TestDocument(t *testing.T) { doc.Marshal(), ) - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { text := root.GetText("k1") text.Style(0, 5, map[string]string{"b": "1"}) assert.Equal( @@ -311,7 +312,7 @@ func TestDocument(t *testing.T) { doc.Marshal(), ) - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { text := root.GetText("k1") text.Edit(5, 11, " Yorkie", nil) assert.Equal( @@ -329,7 +330,7 @@ func TestDocument(t *testing.T) { doc.Marshal(), ) - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { text := root.GetText("k1") text.Edit(5, 5, "\n", map[string]string{"list": "true"}) assert.Equal( @@ -358,7 +359,7 @@ func TestDocument(t *testing.T) { var double = 5.66 // integer type test - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewCounter("age", crdt.IntegerCnt, 5) age := root.GetCounter("age") @@ -375,7 +376,7 @@ func TestDocument(t *testing.T) { assert.Equal(t, "128", doc.Root().GetCounter("age").Counter.Marshal()) // long type test - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewCounter("price", crdt.LongCnt, 9000000000000000000) price := root.GetCounter("price") println(price.ValueType()) @@ -391,7 +392,7 @@ func TestDocument(t *testing.T) { assert.Equal(t, `{"age":128,"price":9000000000000000123}`, doc.Marshal()) // negative operator test - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { age := root.GetCounter("age") age.Increase(-5) age.Increase(-3.14) @@ -407,7 +408,7 @@ func TestDocument(t *testing.T) { // TODO: it should be modified to error check // when 'Remove panic from server code (#50)' is completed. - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { defer func() { r := recover() assert.NotNil(t, r) @@ -427,21 +428,21 @@ func TestDocument(t *testing.T) { t.Run("rollback test", func(t *testing.T) { doc := document.New("d1") - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewArray("k1").AddInteger(1, 2, 3) return nil }) assert.NoError(t, err) assert.Equal(t, `{"k1":[1,2,3]}`, doc.Marshal()) - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { root.GetArray("k1").AddInteger(4, 5) return errDummy }) assert.Equal(t, err, errDummy, "should returns the dummy error") assert.Equal(t, `{"k1":[1,2,3]}`, doc.Marshal()) - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { root.GetArray("k1").AddInteger(4, 5) return nil }) @@ -452,7 +453,7 @@ func TestDocument(t *testing.T) { t.Run("rollback test, primitive deepcopy", func(t *testing.T) { doc := document.New("d1") - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewObject("k1"). SetInteger("k1.1", 1). SetInteger("k1.2", 2) @@ -461,7 +462,7 @@ func TestDocument(t *testing.T) { assert.NoError(t, err) assert.Equal(t, `{"k1":{"k1.1":1,"k1.2":2}}`, doc.Marshal()) - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { root.GetObject("k1").Delete("k1.1") return errDummy }) @@ -472,7 +473,7 @@ func TestDocument(t *testing.T) { t.Run("text garbage collection test", func(t *testing.T) { doc := document.New("d1") - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewText("text") root.GetText("text").Edit(0, 0, "ABCD") root.GetText("text").Edit(0, 2, "12") @@ -494,7 +495,7 @@ func TestDocument(t *testing.T) { doc.Root().GetText("text").StructureAsString(), ) - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { root.GetText("text").Edit(2, 4, "") return nil }) @@ -509,7 +510,7 @@ func TestDocument(t *testing.T) { t.Run("previously inserted elements in heap when running GC test", func(t *testing.T) { doc := document.New("d1") - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetInteger("a", 1) root.SetInteger("a", 2) root.Delete("a") diff --git a/pkg/document/innerpresence/presence.go b/pkg/document/innerpresence/presence.go new file mode 100644 index 000000000..7376d0f02 --- /dev/null +++ b/pkg/document/innerpresence/presence.go @@ -0,0 +1,148 @@ +/* + * Copyright 2023 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Package innerpresence provides the implementation of Presence. +// If the client is watching a document, the presence is shared with +// all other clients watching the same document. +package innerpresence + +import ( + "encoding/json" + "fmt" + "sync" +) + +// Map is a map of Presence. It is wrapper of sync.Map to use type-safe. +type Map struct { + presences sync.Map +} + +// NewMap creates a new instance of Map. +func NewMap() *Map { + return &Map{presences: sync.Map{}} +} + +// Store stores the given presence to the map. +func (m *Map) Store(clientID string, presence Presence) { + m.presences.Store(clientID, presence) +} + +// Range calls f sequentially for each key and value present in the map. +func (m *Map) Range(f func(clientID string, presence Presence) bool) { + m.presences.Range(func(key, value interface{}) bool { + clientID := key.(string) + presence := value.(Presence) + return f(clientID, presence) + }) +} + +// Load returns the presence for the given clientID. +func (m *Map) Load(clientID string) (Presence, bool) { + presence, ok := m.presences.Load(clientID) + if !ok { + return nil, false + } + + return presence.(Presence), true +} + +// LoadOrStore returns the existing presence if exists. +// Otherwise, it stores and returns the given presence. +func (m *Map) LoadOrStore(clientID string, presence Presence) Presence { + actual, _ := m.presences.LoadOrStore(clientID, presence) + return actual.(Presence) +} + +// Has returns whether the given clientID exists. +func (m *Map) Has(clientID string) bool { + _, ok := m.presences.Load(clientID) + return ok +} + +// Delete deletes the presence for the given clientID. +func (m *Map) Delete(clientID string) { + m.presences.Delete(clientID) +} + +// DeepCopy copies itself deeply. +func (m *Map) DeepCopy() *Map { + copied := NewMap() + m.Range(func(clientID string, presence Presence) bool { + copied.Store(clientID, presence.DeepCopy()) + return true + }) + return copied +} + +// PresenceChangeType represents the type of presence change. +type PresenceChangeType string + +const ( + // Put represents the presence is put. + Put PresenceChangeType = "put" + + // Clear represents the presence is cleared. + Clear PresenceChangeType = "clear" +) + +// PresenceChange represents the change of presence. +type PresenceChange struct { + ChangeType PresenceChangeType `json:"changeType"` + Presence Presence `json:"presence"` +} + +// NewChangeFromJSON creates a new instance of PresenceChange from JSON. +func NewChangeFromJSON(encodedChange string) (*PresenceChange, error) { + if encodedChange == "" { + return nil, nil + } + + p := &PresenceChange{} + if err := json.Unmarshal([]byte(encodedChange), p); err != nil { + return nil, fmt.Errorf("unmarshal presence change: %w", err) + } + + return p, nil +} + +// Presence represents custom presence that can be defined by the client. +type Presence map[string]string + +// NewPresence creates a new instance of Presence. +func NewPresence() Presence { + return make(map[string]string) +} + +// Set sets the value of the given key. +func (p Presence) Set(key string, value string) { + p[key] = value +} + +// Clear clears the presence. +func (p Presence) Clear() { + for k := range p { + delete(p, k) + } +} + +// DeepCopy copies itself deeply. +func (p Presence) DeepCopy() Presence { + clone := make(map[string]string) + for k, v := range p { + clone[k] = v + } + return clone +} diff --git a/pkg/document/internal_document.go b/pkg/document/internal_document.go index 9163fc1f9..e4ce0d8fc 100644 --- a/pkg/document/internal_document.go +++ b/pkg/document/internal_document.go @@ -18,10 +18,12 @@ package document import ( "errors" + gosync "sync" "github.com/yorkie-team/yorkie/api/converter" "github.com/yorkie-team/yorkie/pkg/document/change" "github.com/yorkie-team/yorkie/pkg/document/crdt" + "github.com/yorkie-team/yorkie/pkg/document/innerpresence" "github.com/yorkie-team/yorkie/pkg/document/key" "github.com/yorkie-team/yorkie/pkg/document/time" ) @@ -48,13 +50,40 @@ var ( ErrDocumentRemoved = errors.New("document is removed") ) -// InternalDocument represents a document in MongoDB and contains logical clocks. +// InternalDocument is a document that is used internally. It is not directly +// exposed to the user. type InternalDocument struct { - key key.Key - status StatusType - root *crdt.Root - checkpoint change.Checkpoint - changeID change.ID + // key is the key of the document. It is used as the key of the document in + // user's perspective. + key key.Key + + // status is the status of the document. It is used to check whether the + // document is attached to the client or detached or removed. + status StatusType + + // checkpoint is the checkpoint of the document. It is used to determine + // what changes should be sent and what changes should be received. + checkpoint change.Checkpoint + + // changeID is the ID of the last change. It is used to create a new change. + // It contains logical clock information like the lamport timestamp, actorID + // and checkpoint information. + changeID change.ID + + // root is the root of the document. It is used to store JSON-like data in + // CRDT manner. + root *crdt.Root + + // presences is the map of the presence. It is used to store the presence + // of the actors who are attaching this document. + presences *innerpresence.Map + + // onlineClients is the set of the client who is editing this document in + // online. + onlineClients *gosync.Map + + // localChanges is the list of the changes that are not yet sent to the + // server. localChanges []*change.Change } @@ -62,12 +91,15 @@ type InternalDocument struct { func NewInternalDocument(k key.Key) *InternalDocument { root := crdt.NewObject(crdt.NewElementRHT(), time.InitialTicket) + // TODO(hackerwins): We need to initialize the presence of the actor who edited the document. return &InternalDocument{ - key: k, - status: StatusDetached, - root: crdt.NewRoot(root), - checkpoint: change.InitialCheckpoint, - changeID: change.InitialID, + key: k, + status: StatusDetached, + root: crdt.NewRoot(root), + checkpoint: change.InitialCheckpoint, + changeID: change.InitialID, + presences: innerpresence.NewMap(), + onlineClients: &gosync.Map{}, } } @@ -78,17 +110,19 @@ func NewInternalDocumentFromSnapshot( lamport int64, snapshot []byte, ) (*InternalDocument, error) { - obj, err := converter.BytesToObject(snapshot) + obj, presences, err := converter.BytesToSnapshot(snapshot) if err != nil { return nil, err } return &InternalDocument{ - key: k, - status: StatusDetached, - root: crdt.NewRoot(obj), - checkpoint: change.InitialCheckpoint.NextServerSeq(serverSeq), - changeID: change.InitialID.SyncLamport(lamport), + key: k, + status: StatusDetached, + root: crdt.NewRoot(obj), + presences: presences, + onlineClients: &gosync.Map{}, + checkpoint: change.InitialCheckpoint.NextServerSeq(serverSeq), + changeID: change.InitialID.SyncLamport(lamport), }, nil } @@ -109,13 +143,13 @@ func (d *InternalDocument) HasLocalChanges() bool { // ApplyChangePack applies the given change pack into this document. func (d *InternalDocument) ApplyChangePack(pack *change.Pack) error { - // 01. Apply remote changes to both the clone and the document. + // 01. Apply remote changes to both the cloneRoot and the document. if len(pack.Snapshot) > 0 { if err := d.applySnapshot(pack.Snapshot, pack.Checkpoint.ServerSeq); err != nil { return err } } else { - if err := d.ApplyChanges(pack.Changes...); err != nil { + if _, err := d.ApplyChanges(pack.Changes...); err != nil { return err } } @@ -188,7 +222,7 @@ func (d *InternalDocument) SetStatus(status StatusType) { d.status = status } -// IsAttached returns the whether this document is attached or not. +// IsAttached returns whether this document is attached or not. func (d *InternalDocument) IsAttached() bool { return d.status == StatusAttached } @@ -204,25 +238,95 @@ func (d *InternalDocument) RootObject() *crdt.Object { } func (d *InternalDocument) applySnapshot(snapshot []byte, serverSeq int64) error { - rootObj, err := converter.BytesToObject(snapshot) + rootObj, presences, err := converter.BytesToSnapshot(snapshot) if err != nil { return err } d.root = crdt.NewRoot(rootObj) + d.presences = presences d.changeID = d.changeID.SyncLamport(serverSeq) return nil } // ApplyChanges applies remote changes to the document. -func (d *InternalDocument) ApplyChanges(changes ...*change.Change) error { +func (d *InternalDocument) ApplyChanges(changes ...*change.Change) ([]DocEvent, error) { + var events []DocEvent for _, c := range changes { - if err := c.Execute(d.root); err != nil { - return err + if c.PresenceChange() != nil { + clientID := c.ID().ActorID().String() + if _, ok := d.onlineClients.Load(clientID); ok { + event := DocEvent{ + Type: PresenceChangedEvent, + Presences: map[string]innerpresence.Presence{ + clientID: c.PresenceChange().Presence, + }, + } + + if !d.presences.Has(clientID) { + event.Type = WatchedEvent + } + events = append(events, event) + } } + + if err := c.Execute(d.root, d.presences); err != nil { + return nil, err + } + d.changeID = d.changeID.SyncLamport(c.ID().Lamport()) } - return nil + return events, nil +} + +// MyPresence returns the presence of the actor currently editing the document. +func (d *InternalDocument) MyPresence() innerpresence.Presence { + p := d.presences.LoadOrStore(d.changeID.ActorID().String(), innerpresence.NewPresence()) + return p.DeepCopy() +} + +// Presences returns the map of presences of the actors currently editing the document. +func (d *InternalDocument) Presences() *innerpresence.Map { + return d.presences +} + +// OnlinePresence returns the presence of the given client. If the client is not +// online, it returns nil. +func (d *InternalDocument) OnlinePresence(clientID string) innerpresence.Presence { + if _, ok := d.onlineClients.Load(clientID); !ok { + return nil + } + + presence, _ := d.presences.Load(clientID) + return presence +} + +// Presence returns the presence of the given client. +func (d *InternalDocument) Presence(clientID string) innerpresence.Presence { + presence, _ := d.presences.Load(clientID) + return presence +} + +// SetOnlineClientSet sets the online client set. +func (d *InternalDocument) SetOnlineClientSet(ids ...string) { + d.onlineClients.Range(func(key, value interface{}) bool { + d.onlineClients.Delete(key) + return true + }) + + for _, id := range ids { + d.onlineClients.Store(id, true) + } +} + +// AddOnlineClient adds the given client to the online client set. +func (d *InternalDocument) AddOnlineClient(clientID string) { + d.onlineClients.Store(clientID, true) +} + +// RemoveOnlineClient removes the given client from the online client set. +func (d *InternalDocument) RemoveOnlineClient(clientID string) { + d.onlineClients.Delete(clientID) } diff --git a/pkg/document/presence/presence.go b/pkg/document/presence/presence.go new file mode 100644 index 000000000..f9a72fd2b --- /dev/null +++ b/pkg/document/presence/presence.go @@ -0,0 +1,73 @@ +/* + * Copyright 2023 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Package presence provides the proxy for the innerpresence.Presence to be manipulated from the outside. +// TODO(hackerwins): Consider to remove this package. It is used to solve the problem of cyclic dependency +// between pkg/document/presence and pkg/document/change. +package presence + +import ( + "github.com/yorkie-team/yorkie/pkg/document/change" + "github.com/yorkie-team/yorkie/pkg/document/innerpresence" +) + +// Presence represents a proxy for the Presence to be manipulated from the outside. +type Presence struct { + presence innerpresence.Presence + context *change.Context +} + +// New creates a new instance of Presence. +func New(ctx *change.Context, presence innerpresence.Presence) *Presence { + return &Presence{ + presence: presence, + context: ctx, + } +} + +// Initialize initializes the presence. +func (p *Presence) Initialize(presence innerpresence.Presence) { + p.presence = presence + if p.presence == nil { + p.presence = innerpresence.NewPresence() + } + + p.context.SetPresenceChange(innerpresence.PresenceChange{ + ChangeType: innerpresence.Put, + Presence: p.presence, + }) +} + +// Set sets the value of the given key. +func (p *Presence) Set(key string, value string) { + innerPresence := p.presence + innerPresence.Set(key, value) + + p.context.SetPresenceChange(innerpresence.PresenceChange{ + ChangeType: innerpresence.Put, + Presence: innerPresence, + }) +} + +// Clear clears the value of the given key. +func (p *Presence) Clear() { + innerPresence := p.presence + innerPresence.Clear() + + p.context.SetPresenceChange(innerpresence.PresenceChange{ + ChangeType: innerpresence.Clear, + }) +} diff --git a/server/backend/database/change_info.go b/server/backend/database/change_info.go index e0cbce058..bfbf76680 100644 --- a/server/backend/database/change_info.go +++ b/server/backend/database/change_info.go @@ -17,12 +17,15 @@ package database import ( + "encoding/json" "errors" + "fmt" "github.com/yorkie-team/yorkie/api/converter" "github.com/yorkie-team/yorkie/api/types" api "github.com/yorkie-team/yorkie/api/yorkie/v1" "github.com/yorkie-team/yorkie/pkg/document/change" + "github.com/yorkie-team/yorkie/pkg/document/innerpresence" "github.com/yorkie-team/yorkie/pkg/document/operations" "github.com/yorkie-team/yorkie/pkg/document/time" ) @@ -32,14 +35,15 @@ var ErrEncodeOperationFailed = errors.New("encode operations failed") // ChangeInfo is a structure representing information of a change. type ChangeInfo struct { - ID types.ID `bson:"_id"` - DocID types.ID `bson:"doc_id"` - ServerSeq int64 `bson:"server_seq"` - ClientSeq uint32 `bson:"client_seq"` - Lamport int64 `bson:"lamport"` - ActorID types.ID `bson:"actor_id"` - Message string `bson:"message"` - Operations [][]byte `bson:"operations"` + ID types.ID `bson:"_id"` + DocID types.ID `bson:"doc_id"` + ServerSeq int64 `bson:"server_seq"` + ClientSeq uint32 `bson:"client_seq"` + Lamport int64 `bson:"lamport"` + ActorID types.ID `bson:"actor_id"` + Message string `bson:"message"` + Operations [][]byte `bson:"operations"` + PresenceChange string `bson:"presence_change"` } // EncodeOperations encodes the given operations into bytes array. @@ -62,6 +66,20 @@ func EncodeOperations(operations []operations.Operation) ([][]byte, error) { return encodedOps, nil } +// EncodePresenceChange encodes the given presence change into string. +func EncodePresenceChange(p *innerpresence.PresenceChange) (string, error) { + if p == nil { + return "", nil + } + + bytes, err := json.Marshal(p) + if err != nil { + return "", fmt.Errorf("marshal presence change to bytes: %w", err) + } + + return string(bytes), nil +} + // ToChange creates Change model from this ChangeInfo. func (i *ChangeInfo) ToChange() (*change.Change, error) { actorID, err := time.ActorIDFromHex(i.ActorID.String()) @@ -85,7 +103,12 @@ func (i *ChangeInfo) ToChange() (*change.Change, error) { return nil, err } - c := change.New(changeID, i.Message, ops) + p, err := innerpresence.NewChangeFromJSON(i.PresenceChange) + if err != nil { + return nil, err + } + + c := change.New(changeID, i.Message, ops, p) c.SetServerSeq(i.ServerSeq) return c, nil diff --git a/server/backend/database/memory/database.go b/server/backend/database/memory/database.go index f77bdf7d6..93882c313 100644 --- a/server/backend/database/memory/database.go +++ b/server/backend/database/memory/database.go @@ -782,16 +782,21 @@ func (d *DB) CreateChangeInfos( if err != nil { return err } + encodedPresence, err := database.EncodePresenceChange(cn.PresenceChange()) + if err != nil { + return err + } if err := txn.Insert(tblChanges, &database.ChangeInfo{ - ID: newID(), - DocID: docInfo.ID, - ServerSeq: cn.ServerSeq(), - ActorID: types.ID(cn.ID().ActorID().String()), - ClientSeq: cn.ClientSeq(), - Lamport: cn.ID().Lamport(), - Message: cn.Message(), - Operations: encodedOperations, + ID: newID(), + DocID: docInfo.ID, + ServerSeq: cn.ServerSeq(), + ActorID: types.ID(cn.ID().ActorID().String()), + ClientSeq: cn.ClientSeq(), + Lamport: cn.ID().Lamport(), + Message: cn.Message(), + Operations: encodedOperations, + PresenceChange: encodedPresence, }); err != nil { return fmt.Errorf("create change: %w", err) } @@ -942,7 +947,7 @@ func (d *DB) CreateSnapshotInfo( docID types.ID, doc *document.InternalDocument, ) error { - snapshot, err := converter.ObjectToBytes(doc.RootObject()) + snapshot, err := converter.SnapshotToBytes(doc.RootObject(), doc.Presences()) if err != nil { return err } diff --git a/server/backend/database/mongo/client.go b/server/backend/database/mongo/client.go index 25feb5e3e..bdcdc460a 100644 --- a/server/backend/database/mongo/client.go +++ b/server/backend/database/mongo/client.go @@ -864,16 +864,21 @@ func (c *Client) CreateChangeInfos( if err != nil { return err } + encodedPresence, err := database.EncodePresenceChange(cn.PresenceChange()) + if err != nil { + return err + } models = append(models, mongo.NewUpdateOneModel().SetFilter(bson.M{ "doc_id": encodedDocID, "server_seq": cn.ServerSeq(), }).SetUpdate(bson.M{"$set": bson.M{ - "actor_id": encodeActorID(cn.ID().ActorID()), - "client_seq": cn.ID().ClientSeq(), - "lamport": cn.ID().Lamport(), - "message": cn.Message(), - "operations": encodedOperations, + "actor_id": encodeActorID(cn.ID().ActorID()), + "client_seq": cn.ID().ClientSeq(), + "lamport": cn.ID().Lamport(), + "message": cn.Message(), + "operations": encodedOperations, + "presence_change": encodedPresence, }}).SetUpsert(true)) } @@ -1026,7 +1031,7 @@ func (c *Client) CreateSnapshotInfo( if err != nil { return err } - snapshot, err := converter.ObjectToBytes(doc.RootObject()) + snapshot, err := converter.SnapshotToBytes(doc.RootObject(), doc.Presences()) if err != nil { return err } diff --git a/server/backend/database/testcases/testcases.go b/server/backend/database/testcases/testcases.go index c07140809..e1fcbca7a 100644 --- a/server/backend/database/testcases/testcases.go +++ b/server/backend/database/testcases/testcases.go @@ -33,6 +33,7 @@ import ( "github.com/yorkie-team/yorkie/pkg/document/change" "github.com/yorkie-team/yorkie/pkg/document/json" "github.com/yorkie-team/yorkie/pkg/document/key" + "github.com/yorkie-team/yorkie/pkg/document/presence" "github.com/yorkie-team/yorkie/pkg/document/time" "github.com/yorkie-team/yorkie/server/backend/database" "github.com/yorkie-team/yorkie/test/helper" @@ -175,12 +176,12 @@ func RunFindChangesBetweenServerSeqsTest( actorID, _ := time.ActorIDFromBytes(bytesID) doc := document.New(key.Key(t.Name())) doc.SetActor(actorID) - assert.NoError(t, doc.Update(func(root *json.Object) error { + assert.NoError(t, doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewArray("array") return nil })) for idx := 0; idx < 10; idx++ { - assert.NoError(t, doc.Update(func(root *json.Object) error { + assert.NoError(t, doc.Update(func(root *json.Object, p *presence.Presence) error { root.GetArray("array").AddInteger(idx) return nil })) @@ -220,7 +221,7 @@ func RunFindClosestSnapshotInfoTest(t *testing.T, db database.Database, projectI doc := document.New(key.Key(t.Name())) doc.SetActor(actorID) - assert.NoError(t, doc.Update(func(root *json.Object) error { + assert.NoError(t, doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewArray("array") return nil })) diff --git a/server/backend/sync/coordinator.go b/server/backend/sync/coordinator.go index ff70e1006..deab2105c 100644 --- a/server/backend/sync/coordinator.go +++ b/server/backend/sync/coordinator.go @@ -40,9 +40,9 @@ type Coordinator interface { // Subscribe subscribes to the given documents. Subscribe( ctx context.Context, - subscriber types.Client, + subscriber *time.ActorID, documentID types.ID, - ) (*Subscription, []types.Client, error) + ) (*Subscription, []*time.ActorID, error) // Unsubscribe unsubscribes from the given documents. Unsubscribe( @@ -57,13 +57,6 @@ type Coordinator interface { // PublishToLocal publishes the given event. PublishToLocal(ctx context.Context, publisherID *time.ActorID, event DocEvent) - // UpdatePresence updates the presence of the given client. - UpdatePresence( - ctx context.Context, - publisher *types.Client, - documentID types.ID, - ) error - // Members returns the members of this cluster. Members() map[string]*ServerInfo diff --git a/server/backend/sync/memory/coordinator.go b/server/backend/sync/memory/coordinator.go index 9b08a1cc1..57b6ca909 100644 --- a/server/backend/sync/memory/coordinator.go +++ b/server/backend/sync/memory/coordinator.go @@ -57,16 +57,16 @@ func (c *Coordinator) NewLocker( // Subscribe subscribes to the given documents. func (c *Coordinator) Subscribe( ctx context.Context, - subscriber types.Client, + subscriber *time.ActorID, documentID types.ID, -) (*sync.Subscription, []types.Client, error) { +) (*sync.Subscription, []*time.ActorID, error) { sub, err := c.pubSub.Subscribe(ctx, subscriber, documentID) if err != nil { return nil, nil, err } - peers := c.pubSub.GetPeers(documentID) - return sub, peers, nil + ids := c.pubSub.ClientIDs(documentID) + return sub, ids, nil } // Unsubscribe unsubscribes the given documents. @@ -97,16 +97,6 @@ func (c *Coordinator) PublishToLocal( c.pubSub.Publish(ctx, publisherID, event) } -// UpdatePresence updates the presence of the given client. -func (c *Coordinator) UpdatePresence( - _ context.Context, - publisher *types.Client, - documentID types.ID, -) error { - c.pubSub.UpdatePresence(publisher, documentID) - return nil -} - // Members returns the members of this cluster. func (c *Coordinator) Members() map[string]*sync.ServerInfo { members := make(map[string]*sync.ServerInfo) diff --git a/server/backend/sync/memory/coordinator_test.go b/server/backend/sync/memory/coordinator_test.go index a0ae2594d..02e2e5ce4 100644 --- a/server/backend/sync/memory/coordinator_test.go +++ b/server/backend/sync/memory/coordinator_test.go @@ -37,9 +37,9 @@ func TestCoordinator(t *testing.T) { id, err := time.ActorIDFromBytes([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, byte(i)}) assert.NoError(t, err) - _, peers, err := coordinator.Subscribe(ctx, types.Client{ID: id}, docID) + _, clientIDs, err := coordinator.Subscribe(ctx, id, docID) assert.NoError(t, err) - assert.Len(t, peers, i+1) + assert.Len(t, clientIDs, i+1) } }) } diff --git a/server/backend/sync/memory/pubsub.go b/server/backend/sync/memory/pubsub.go index 733a15eec..a01703784 100644 --- a/server/backend/sync/memory/pubsub.go +++ b/server/backend/sync/memory/pubsub.go @@ -65,31 +65,29 @@ func (s *subscriptions) Len() int { // PubSub is the memory implementation of PubSub, used for single server. type PubSub struct { - subscriptionsMapMu *gosync.RWMutex - subscriptionMapBySubscriber map[string]*sync.Subscription - subscriptionsMapByDocID map[types.ID]*subscriptions + subscriptionsMapMu *gosync.RWMutex + subscriptionsMapByDocID map[types.ID]*subscriptions } // NewPubSub creates an instance of PubSub. func NewPubSub() *PubSub { return &PubSub{ - subscriptionsMapMu: &gosync.RWMutex{}, - subscriptionMapBySubscriber: make(map[string]*sync.Subscription), - subscriptionsMapByDocID: make(map[types.ID]*subscriptions), + subscriptionsMapMu: &gosync.RWMutex{}, + subscriptionsMapByDocID: make(map[types.ID]*subscriptions), } } // Subscribe subscribes to the given document keys. func (m *PubSub) Subscribe( ctx context.Context, - subscriber types.Client, + subscriber *time.ActorID, documentID types.ID, ) (*sync.Subscription, error) { if logging.Enabled(zap.DebugLevel) { logging.From(ctx).Debugf( `Subscribe(%s,%s) Start`, documentID.String(), - subscriber.ID.String(), + subscriber.String(), ) } @@ -97,8 +95,6 @@ func (m *PubSub) Subscribe( defer m.subscriptionsMapMu.Unlock() sub := sync.NewSubscription(subscriber) - m.subscriptionMapBySubscriber[sub.SubscriberID()] = sub - if _, ok := m.subscriptionsMapByDocID[documentID]; !ok { m.subscriptionsMapByDocID[documentID] = newSubscriptions() } @@ -108,7 +104,7 @@ func (m *PubSub) Subscribe( logging.From(ctx).Debugf( `Subscribe(%s,%s) End`, documentID.String(), - subscriber.ID.String(), + subscriber.String(), ) } return sub, nil @@ -127,14 +123,12 @@ func (m *PubSub) Unsubscribe( logging.From(ctx).Debugf( `Unsubscribe(%s,%s) Start`, documentID, - sub.SubscriberID(), + sub.Subscriber().String(), ) } sub.Close() - delete(m.subscriptionMapBySubscriber, sub.SubscriberID()) - if subs, ok := m.subscriptionsMapByDocID[documentID]; ok { subs.Delete(sub.ID()) @@ -147,7 +141,7 @@ func (m *PubSub) Unsubscribe( logging.From(ctx).Debugf( `Unsubscribe(%s,%s) End`, documentID, - sub.SubscriberID(), + sub.Subscriber().String(), ) } } @@ -168,7 +162,7 @@ func (m *PubSub) Publish( if subs, ok := m.subscriptionsMapByDocID[documentID]; ok { for _, sub := range subs.Map() { - if sub.Subscriber().ID.Compare(publisherID) == 0 { + if sub.Subscriber().Compare(publisherID) == 0 { continue } @@ -178,7 +172,7 @@ func (m *PubSub) Publish( event.Type, documentID.String(), publisherID.String(), - sub.SubscriberID(), + sub.Subscriber().String(), ) } @@ -191,7 +185,7 @@ func (m *PubSub) Publish( `Publish(%s,%s) to %s timeout`, documentID.String(), publisherID.String(), - sub.SubscriberID(), + sub.Subscriber().String(), ) } } @@ -201,31 +195,14 @@ func (m *PubSub) Publish( } } -// GetPeers returns the peers of the given document. -func (m *PubSub) GetPeers(documentID types.ID) []types.Client { +// ClientIDs returns the clients of the given document. +func (m *PubSub) ClientIDs(documentID types.ID) []*time.ActorID { m.subscriptionsMapMu.RLock() defer m.subscriptionsMapMu.RUnlock() - var peers []types.Client + var ids []*time.ActorID for _, sub := range m.subscriptionsMapByDocID[documentID].Map() { - peers = append(peers, sub.Subscriber()) - } - return peers -} - -// UpdatePresence updates the presence of the given client. -func (m *PubSub) UpdatePresence( - publisher *types.Client, - documentID types.ID, -) *sync.Subscription { - m.subscriptionsMapMu.Lock() - defer m.subscriptionsMapMu.Unlock() - - sub, ok := m.subscriptionMapBySubscriber[publisher.ID.String()] - if !ok { - return nil + ids = append(ids, sub.Subscriber()) } - - sub.UpdatePresence(publisher.PresenceInfo) - return sub + return ids } diff --git a/server/backend/sync/memory/pubsub_test.go b/server/backend/sync/memory/pubsub_test.go index 686991ca5..138ec680c 100644 --- a/server/backend/sync/memory/pubsub_test.go +++ b/server/backend/sync/memory/pubsub_test.go @@ -34,21 +34,19 @@ func TestPubSub(t *testing.T) { assert.NoError(t, err) idB, err := time.ActorIDFromBytes([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}) assert.NoError(t, err) - actorA := types.Client{ID: idA} - actorB := types.Client{ID: idB} t.Run("publish subscribe test", func(t *testing.T) { pubSub := memory.NewPubSub() id := types.ID(t.Name() + "id") docEvent := sync.DocEvent{ Type: types.DocumentsWatchedEvent, - Publisher: actorB, + Publisher: idB, DocumentID: id, } ctx := context.Background() // subscribe the documents by actorA - subA, err := pubSub.Subscribe(ctx, actorA, id) + subA, err := pubSub.Subscribe(ctx, idA, id) assert.NoError(t, err) defer func() { pubSub.Unsubscribe(ctx, id, subA) @@ -63,7 +61,7 @@ func TestPubSub(t *testing.T) { }() // publish the event to the documents by actorB - pubSub.Publish(ctx, actorB.ID, docEvent) + pubSub.Publish(ctx, idB, docEvent) wg.Wait() }) } diff --git a/server/backend/sync/pubsub.go b/server/backend/sync/pubsub.go index f66e33000..80ce74164 100644 --- a/server/backend/sync/pubsub.go +++ b/server/backend/sync/pubsub.go @@ -20,18 +20,19 @@ import ( "github.com/rs/xid" "github.com/yorkie-team/yorkie/api/types" + "github.com/yorkie-team/yorkie/pkg/document/time" ) // Subscription represents a subscription of a subscriber to documents. type Subscription struct { id string - subscriber types.Client + subscriber *time.ActorID closed bool events chan DocEvent } // NewSubscription creates a new instance of Subscription. -func NewSubscription(subscriber types.Client) *Subscription { +func NewSubscription(subscriber *time.ActorID) *Subscription { return &Subscription{ id: xid.New().String(), subscriber: subscriber, @@ -47,7 +48,7 @@ func (s *Subscription) ID() string { // DocEvent represents events that occur related to the document. type DocEvent struct { Type types.DocEventType - Publisher types.Client + Publisher *time.ActorID DocumentID types.ID } @@ -57,20 +58,10 @@ func (s *Subscription) Events() chan DocEvent { } // Subscriber returns the subscriber of this subscription. -func (s *Subscription) Subscriber() types.Client { +func (s *Subscription) Subscriber() *time.ActorID { return s.subscriber } -// SubscriberID returns string representation of the subscriber. -func (s *Subscription) SubscriberID() string { - return s.subscriber.ID.String() -} - -// UpdatePresence updates the presence of the subscriber. -func (s *Subscription) UpdatePresence(info types.PresenceInfo) { - s.subscriber.PresenceInfo.Update(info) -} - // Close closes all resources of this Subscription. func (s *Subscription) Close() { if s.closed { diff --git a/server/clients/clients.go b/server/clients/clients.go index ab6c6691c..1803c7f17 100644 --- a/server/clients/clients.go +++ b/server/clients/clients.go @@ -73,6 +73,11 @@ func Deactivate( return nil, err } + // TODO(hackerwins): We need to remove the presence of the client from the document. + // Be careful that housekeeping is executed by the leader. And documents are sharded + // by the servers in the cluster. So, we need to consider the case where the leader is + // not the same as the server that handles the document. + if err := db.UpdateSyncedSeq( ctx, clientInfo, diff --git a/server/packs/packs.go b/server/packs/packs.go index f27910ab6..159abf1e5 100644 --- a/server/packs/packs.go +++ b/server/packs/packs.go @@ -133,7 +133,7 @@ func PushPull( publisherID, sync.DocEvent{ Type: types.DocumentsChangedEvent, - Publisher: types.Client{ID: publisherID}, + Publisher: publisherID, DocumentID: docInfo.ID, }, ) diff --git a/server/packs/pushpull.go b/server/packs/pushpull.go index 9d30494be..2eb0b95ae 100644 --- a/server/packs/pushpull.go +++ b/server/packs/pushpull.go @@ -157,7 +157,7 @@ func pullSnapshot( } cpAfterPull := cpAfterPush.NextServerSeq(docInfo.ServerSeq) - snapshot, err := converter.ObjectToBytes(doc.RootObject()) + snapshot, err := converter.SnapshotToBytes(doc.RootObject(), doc.Presences()) if err != nil { return nil, err } diff --git a/server/packs/serverpacks.go b/server/packs/serverpacks.go index cf51db0e5..e36f75009 100644 --- a/server/packs/serverpacks.go +++ b/server/packs/serverpacks.go @@ -20,6 +20,7 @@ import ( "github.com/yorkie-team/yorkie/api/converter" api "github.com/yorkie-team/yorkie/api/yorkie/v1" "github.com/yorkie-team/yorkie/pkg/document/change" + "github.com/yorkie-team/yorkie/pkg/document/innerpresence" "github.com/yorkie-team/yorkie/pkg/document/key" "github.com/yorkie-team/yorkie/pkg/document/time" "github.com/yorkie-team/yorkie/server/backend/database" @@ -101,10 +102,16 @@ func (p *ServerPack) ToPBChangePack() (*api.ChangePack, error) { pbOps = append(pbOps, &pbOp) } + p, err := innerpresence.NewChangeFromJSON(info.PresenceChange) + if err != nil { + return nil, err + } + pbChanges = append(pbChanges, &api.Change{ - Id: converter.ToChangeID(changeID), - Message: info.Message, - Operations: pbOps, + Id: converter.ToChangeID(changeID), + Message: info.Message, + Operations: pbOps, + PresenceChange: converter.ToPresenceChange(p), }) } diff --git a/server/rpc/admin_server.go b/server/rpc/admin_server.go index a25761f38..3487b1ee9 100644 --- a/server/rpc/admin_server.go +++ b/server/rpc/admin_server.go @@ -254,7 +254,7 @@ func (s *adminServer) GetSnapshotMeta( return nil, err } - snapshot, err := converter.ObjectToBytes(doc.RootObject()) + snapshot, err := converter.SnapshotToBytes(doc.RootObject(), doc.Presences()) if err != nil { return nil, err } @@ -376,7 +376,7 @@ func (s *adminServer) RemoveDocumentByAdmin( publisherID, sync.DocEvent{ Type: types.DocumentsChangedEvent, - Publisher: types.Client{ID: publisherID}, + Publisher: publisherID, DocumentID: docInfo.ID, }, ) diff --git a/server/rpc/server_test.go b/server/rpc/server_test.go index 36de756d4..e883d0e91 100644 --- a/server/rpc/server_test.go +++ b/server/rpc/server_test.go @@ -672,7 +672,7 @@ func TestSDKRPCServerBackend(t *testing.T) { watchResp, err := testClient.WatchDocument( context.Background(), &api.WatchDocumentRequest{ - Client: &api.Client{Id: activateResp.ClientId, Presence: &api.Presence{}}, + ClientId: activateResp.ClientId, DocumentId: resPack.DocumentId, }, ) diff --git a/server/rpc/yorkie_server.go b/server/rpc/yorkie_server.go index ab1f46c07..5bf8f918d 100644 --- a/server/rpc/yorkie_server.go +++ b/server/rpc/yorkie_server.go @@ -236,11 +236,15 @@ func (s *yorkieServer) DetachDocument( return nil, err } - if err := clientInfo.RemoveDocument(docInfo.ID); err != nil { - return nil, err - } if req.RemoveIfNotAttached && !isAttached { pack.IsRemoved = true + if err := clientInfo.RemoveDocument(docInfo.ID); err != nil { + return nil, err + } + } else { + if err := clientInfo.DetachDocument(docInfo.ID); err != nil { + return nil, err + } } pulled, err := packs.PushPull(ctx, s.backend, project, clientInfo, docInfo, pack, types.SyncModePushPull) @@ -344,7 +348,7 @@ func (s *yorkieServer) WatchDocument( req *api.WatchDocumentRequest, stream api.YorkieService_WatchDocumentServer, ) error { - cli, err := converter.FromClient(req.Client) + clientID, err := time.ActorIDFromBytes(req.ClientId) if err != nil { return err } @@ -371,13 +375,13 @@ func (s *yorkieServer) WatchDocument( } project := projects.From(stream.Context()) - if _, err = clients.FindClientInfo(stream.Context(), s.backend.DB, project, cli.ID); err != nil { + if _, err = clients.FindClientInfo(stream.Context(), s.backend.DB, project, clientID); err != nil { return err } locker, err := s.backend.Coordinator.NewLocker( stream.Context(), - sync.NewKey(fmt.Sprintf("watchdoc-%s-%s", cli.ID.String(), docID)), + sync.NewKey(fmt.Sprintf("watchdoc-%s-%s", clientID.String(), docID)), ) if err != nil { return err @@ -391,7 +395,7 @@ func (s *yorkieServer) WatchDocument( } }() - subscription, peersMap, err := s.watchDoc(stream.Context(), *cli, docID) + subscription, clientIDs, err := s.watchDoc(stream.Context(), clientID, docID) if err != nil { logging.From(stream.Context()).Error(err) return err @@ -400,10 +404,14 @@ func (s *yorkieServer) WatchDocument( s.unwatchDoc(subscription, docID) }() + var pbClientIDs [][]byte + for _, id := range clientIDs { + pbClientIDs = append(pbClientIDs, id.Bytes()) + } if err := stream.Send(&api.WatchDocumentResponse{ Body: &api.WatchDocumentResponse_Initialization_{ Initialization: &api.WatchDocumentResponse_Initialization{ - Peers: converter.ToClients(peersMap), + ClientIds: pbClientIDs, }, }, }); err != nil { @@ -425,9 +433,8 @@ func (s *yorkieServer) WatchDocument( if err := stream.Send(&api.WatchDocumentResponse{ Body: &api.WatchDocumentResponse_Event{ Event: &api.DocEvent{ - Type: eventType, - Publisher: converter.ToClient(event.Publisher), - DocumentId: event.DocumentID.String(), + Type: eventType, + Publisher: event.Publisher.Bytes(), }, }, }); err != nil { @@ -508,45 +515,12 @@ func (s *yorkieServer) RemoveDocument( }, nil } -// UpdatePresence updates the presence of the given client. -func (s *yorkieServer) UpdatePresence( - ctx context.Context, - req *api.UpdatePresenceRequest, -) (*api.UpdatePresenceResponse, error) { - cli, err := converter.FromClient(req.Client) - if err != nil { - return nil, err - } - documentID, err := converter.FromDocumentID(req.DocumentId) - if err != nil { - return nil, err - } - - project := projects.From(ctx) - _, err = documents.FindDocInfo(ctx, s.backend, project, documentID) - if err != nil { - return nil, err - } - - if err = s.backend.Coordinator.UpdatePresence(ctx, cli, documentID); err != nil { - return nil, err - } - - s.backend.Coordinator.Publish(ctx, cli.ID, sync.DocEvent{ - Type: types.PresenceChangedEvent, - Publisher: *cli, - DocumentID: documentID, - }) - - return &api.UpdatePresenceResponse{}, nil -} - func (s *yorkieServer) watchDoc( ctx context.Context, - client types.Client, + clientID *time.ActorID, documentID types.ID, -) (*sync.Subscription, []types.Client, error) { - subscription, peers, err := s.backend.Coordinator.Subscribe(ctx, client, documentID) +) (*sync.Subscription, []*time.ActorID, error) { + subscription, clientIDs, err := s.backend.Coordinator.Subscribe(ctx, clientID, documentID) if err != nil { logging.From(ctx).Error(err) return nil, nil, err @@ -554,7 +528,7 @@ func (s *yorkieServer) watchDoc( s.backend.Coordinator.Publish( ctx, - subscription.Subscriber().ID, + subscription.Subscriber(), sync.DocEvent{ Type: types.DocumentsWatchedEvent, Publisher: subscription.Subscriber(), @@ -562,7 +536,7 @@ func (s *yorkieServer) watchDoc( }, ) - return subscription, peers, nil + return subscription, clientIDs, nil } func (s *yorkieServer) unwatchDoc( @@ -573,7 +547,7 @@ func (s *yorkieServer) unwatchDoc( _ = s.backend.Coordinator.Unsubscribe(ctx, documentID, subscription) s.backend.Coordinator.Publish( ctx, - subscription.Subscriber().ID, + subscription.Subscriber(), sync.DocEvent{ Type: types.DocumentsUnwatchedEvent, Publisher: subscription.Subscriber(), diff --git a/test/bench/document_bench_test.go b/test/bench/document_bench_test.go index d71f28895..2f43393a0 100644 --- a/test/bench/document_bench_test.go +++ b/test/bench/document_bench_test.go @@ -29,6 +29,7 @@ import ( "github.com/yorkie-team/yorkie/pkg/document/change" "github.com/yorkie-team/yorkie/pkg/document/crdt" "github.com/yorkie-team/yorkie/pkg/document/json" + "github.com/yorkie-team/yorkie/pkg/document/presence" "github.com/yorkie-team/yorkie/pkg/document/time" ) @@ -57,7 +58,7 @@ func BenchmarkDocument(b *testing.B) { doc2 := document.New("d2") doc3 := document.New("d3") - err := doc1.Update(func(root *json.Object) error { + err := doc1.Update(func(root *json.Object, p *presence.Presence) error { root.SetString("k1", "v1") return nil }, "updates k1") @@ -76,7 +77,7 @@ func BenchmarkDocument(b *testing.B) { assert.Equal(b, "{}", doc.Marshal()) assert.False(b, doc.HasLocalChanges()) - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetString("k1", "v1") root.SetNewObject("k2").SetString("k4", "v4") root.SetNewArray("k3").AddString("v5", "v6") @@ -97,7 +98,7 @@ func BenchmarkDocument(b *testing.B) { assert.False(b, doc.HasLocalChanges()) expected := `{"k1":"v1","k2":{"k4":"v4"},"k3":["v5","v6"]}` - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetString("k1", "v1") root.SetNewObject("k2").SetString("k4", "v4") root.SetNewArray("k3").AddString("v5", "v6") @@ -108,7 +109,7 @@ func BenchmarkDocument(b *testing.B) { assert.Equal(b, expected, doc.Marshal()) expected = `{"k1":"v1","k3":["v5","v6"]}` - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { root.Delete("k2") assert.Equal(b, expected, root.Marshal()) return nil @@ -121,7 +122,7 @@ func BenchmarkDocument(b *testing.B) { b.Run("object test", func(b *testing.B) { for i := 0; i < b.N; i++ { doc := document.New("d1") - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetString("k1", "v1") assert.Equal(b, `{"k1":"v1"}`, root.Marshal()) root.SetString("k1", "v2") @@ -137,7 +138,7 @@ func BenchmarkDocument(b *testing.B) { for i := 0; i < b.N; i++ { doc := document.New("d1") - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewArray("k1").AddInteger(1).AddInteger(2).AddInteger(3) assert.Equal(b, 3, root.GetArray("k1").Len()) assert.Equal(b, `{"k1":[1,2,3]}`, root.Marshal()) @@ -180,7 +181,7 @@ func BenchmarkDocument(b *testing.B) { // ---------- ins links -------- // | | | // [init] - [A] - [12] - [BC deleted] - [D] - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewText("k1"). Edit(0, 0, "ABCD"). Edit(1, 3, "12") @@ -190,7 +191,7 @@ func BenchmarkDocument(b *testing.B) { assert.NoError(b, err) assert.Equal(b, `{"k1":[{"val":"A"},{"val":"12"},{"val":"D"}]}`, doc.Marshal()) - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { text := root.GetText("k1") assert.Equal(b, `[0:0:00:0 {} ""][1:2:00:0 {} "A"][1:3:00:0 {} "12"]{1:2:00:1 {} "BC"}[1:2:00:3 {} "D"]`, @@ -221,7 +222,7 @@ func BenchmarkDocument(b *testing.B) { for i := 0; i < b.N; i++ { doc := document.New("d1") - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewText("k1"). Edit(0, 0, "ㅎ"). Edit(0, 1, "하"). @@ -241,7 +242,7 @@ func BenchmarkDocument(b *testing.B) { for i := 0; i < b.N; i++ { doc := document.New("d1") - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { text := root.SetNewText("k1") text.Edit(0, 0, "Hello world", nil) assert.Equal( @@ -254,7 +255,7 @@ func BenchmarkDocument(b *testing.B) { assert.NoError(b, err) assert.Equal(b, `{"k1":[{"val":"Hello world"}]}`, doc.Marshal()) - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { text := root.GetText("k1") text.Style(0, 5, map[string]string{"b": "1"}) assert.Equal(b, @@ -270,7 +271,7 @@ func BenchmarkDocument(b *testing.B) { doc.Marshal(), ) - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { text := root.GetText("k1") text.Style(0, 5, map[string]string{"b": "1"}) assert.Equal( @@ -294,7 +295,7 @@ func BenchmarkDocument(b *testing.B) { doc.Marshal(), ) - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { text := root.GetText("k1") text.Edit(5, 11, " Yorkie", nil) assert.Equal( @@ -312,7 +313,7 @@ func BenchmarkDocument(b *testing.B) { doc.Marshal(), ) - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { text := root.GetText("k1") text.Edit(5, 5, "\n", map[string]string{"list": "true"}) assert.Equal( @@ -341,7 +342,7 @@ func BenchmarkDocument(b *testing.B) { var double = 5.66 // integer type test - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewCounter("age", crdt.IntegerCnt, 5) age := root.GetCounter("age") @@ -357,7 +358,7 @@ func BenchmarkDocument(b *testing.B) { assert.Equal(b, `{"age":128}`, doc.Marshal()) // long type test - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewCounter("price", crdt.LongCnt, 9000000000000000000) price := root.GetCounter("price") price.Increase(long) @@ -372,7 +373,7 @@ func BenchmarkDocument(b *testing.B) { assert.Equal(b, `{"age":128,"price":9000000000000000123}`, doc.Marshal()) // negative operator test - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { age := root.GetCounter("age") age.Increase(-5) age.Increase(-3.14) @@ -388,7 +389,7 @@ func BenchmarkDocument(b *testing.B) { // TODO: it should be modified to error check // when 'Remove panic from server code (#50)' is completed. - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { defer func() { r := recover() assert.NotNil(b, r) @@ -475,7 +476,7 @@ func benchmarkText(cnt int, b *testing.B) { for i := 0; i < b.N; i++ { doc := document.New("d1") - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { text := root.SetNewText("k1") for c := 0; c < cnt; c++ { text.Edit(c, c, "a") @@ -491,7 +492,7 @@ func benchmarkTextDeleteAll(cnt int, b *testing.B) { b.StopTimer() doc := document.New("d1") - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { text := root.SetNewText("k1") for c := 0; c < cnt; c++ { text.Edit(c, c, "a") @@ -501,7 +502,7 @@ func benchmarkTextDeleteAll(cnt int, b *testing.B) { assert.NoError(b, err) b.StartTimer() - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { text := root.GetText("k1") text.Edit(0, cnt, "") return nil @@ -518,7 +519,7 @@ func benchmarkTextEditGC(cnt int, b *testing.B) { assert.Equal(b, "{}", doc.Marshal()) assert.False(b, doc.HasLocalChanges()) - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { text := root.SetNewText("k1") for i := 0; i < cnt; i++ { text.Edit(i, i, "a") @@ -527,7 +528,7 @@ func benchmarkTextEditGC(cnt int, b *testing.B) { }, "creates a text then appends a") assert.NoError(b, err) - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { text := root.GetText("k1") for i := 0; i < cnt; i++ { text.Edit(i, i+1, "b") @@ -549,14 +550,14 @@ func benchmarkTextSplitGC(cnt int, b *testing.B) { for i := 0; i < cnt; i++ { builder.WriteString("a") } - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { text := root.SetNewText("k2") text.Edit(0, 0, builder.String()) return nil }, "initial") assert.NoError(b, err) - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { text := root.GetText("k2") for i := 0; i < cnt; i++ { if i != cnt { @@ -576,7 +577,7 @@ func benchmarkArray(cnt int, b *testing.B) { for i := 0; i < b.N; i++ { doc := document.New("d1") - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { array := root.SetNewArray("k1") for c := 0; c < cnt; c++ { array.AddInteger(c) @@ -590,7 +591,7 @@ func benchmarkArray(cnt int, b *testing.B) { func benchmarkArrayGC(cnt int, b *testing.B) { for i := 0; i < b.N; i++ { doc := document.New("d1") - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewArray("1") for i := 0; i < cnt; i++ { root.GetArray("1").AddInteger(i) @@ -600,7 +601,7 @@ func benchmarkArrayGC(cnt int, b *testing.B) { }, "creates an array then adds integers") assert.NoError(b, err) - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { root.Delete("1") return nil }, "deletes the array") @@ -615,7 +616,7 @@ func benchmarkCounter(cnt int, b *testing.B) { for i := 0; i < b.N; i++ { doc := document.New("d1") - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { counter := root.SetNewCounter("k1", crdt.IntegerCnt, 0) for c := 0; c < cnt; c++ { counter.Increase(c) @@ -630,7 +631,7 @@ func benchmarkObject(cnt int, b *testing.B) { for i := 0; i < b.N; i++ { doc := document.New("d1") - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { for c := 0; c < cnt; c++ { root.SetInteger("k1", c) } diff --git a/test/bench/grpc_bench_test.go b/test/bench/grpc_bench_test.go index 9279bfd60..05650a643 100644 --- a/test/bench/grpc_bench_test.go +++ b/test/bench/grpc_bench_test.go @@ -34,6 +34,7 @@ import ( "github.com/yorkie-team/yorkie/pkg/document" "github.com/yorkie-team/yorkie/pkg/document/json" "github.com/yorkie-team/yorkie/pkg/document/key" + "github.com/yorkie-team/yorkie/pkg/document/presence" "github.com/yorkie-team/yorkie/server" "github.com/yorkie-team/yorkie/server/backend/database" "github.com/yorkie-team/yorkie/server/logging" @@ -60,7 +61,7 @@ func activeClients(b *testing.B, n int) (clients []*client.Client) { for i := 0; i < n; i++ { c, err := client.Dial( defaultServer.RPCAddr(), - client.WithMaxRecvMsgSize(int(10*1024*1024)), + client.WithMaxRecvMsgSize(50*1024*1024), ) assert.NoError(b, err) @@ -89,7 +90,7 @@ func benchmarkUpdateAndSync( key string, ) { for i := 0; i < cnt; i++ { - err := d.Update(func(root *json.Object) error { + err := d.Update(func(root *json.Object, p *presence.Presence) error { text := root.GetText(key) text.Edit(0, 0, "c") return nil @@ -129,6 +130,7 @@ func watchDoc( ctx context.Context, b *testing.B, cli *client.Client, + d *document.Document, rch <-chan client.WatchResponse, done <-chan bool, ) { @@ -140,8 +142,8 @@ func watchDoc( } assert.NoError(b, resp.Err) - if resp.Type == client.DocumentsChanged { - err := cli.Sync(ctx, client.WithDocKey(resp.Key)) + if resp.Type == client.DocumentChanged { + err := cli.Sync(ctx, client.WithDocKey(d.Key())) assert.NoError(b, err) } case <-done: @@ -184,7 +186,7 @@ func BenchmarkRPC(b *testing.B) { for i := 0; i < b.N; i++ { testKey := "testKey" - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewText(testKey) return nil }) @@ -205,7 +207,7 @@ func BenchmarkRPC(b *testing.B) { err := c1.Attach(ctx, d1) assert.NoError(b, err) testKey1 := "testKey1" - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewText(testKey1) return nil }) @@ -215,7 +217,7 @@ func BenchmarkRPC(b *testing.B) { err = c2.Attach(ctx, d2) assert.NoError(b, err) testKey2 := "testKey2" - err = d2.Update(func(root *json.Object) error { + err = d2.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewText(testKey2) return nil }) @@ -230,16 +232,15 @@ func BenchmarkRPC(b *testing.B) { done2 := make(chan bool) for i := 0; i < b.N; i++ { - wg := sync.WaitGroup{} wg.Add(2) go func() { defer wg.Done() - watchDoc(ctx, b, c1, rch1, done2) + watchDoc(ctx, b, c1, d1, rch1, done2) }() go func() { defer wg.Done() - watchDoc(ctx, b, c2, rch2, done1) + watchDoc(ctx, b, c2, d2, rch2, done1) }() go func() { @@ -270,13 +271,13 @@ func BenchmarkRPC(b *testing.B) { doc1 := document.New(key.Key(helper.TestDocKey(b))) doc2 := document.New(key.Key(helper.TestDocKey(b))) - err := doc1.Update(func(root *json.Object) error { + err := doc1.Update(func(root *json.Object, p *presence.Presence) error { text := root.SetNewText("k1") text.Edit(0, 0, builder.String()) return nil }) assert.NoError(b, err) - err = doc2.Update(func(root *json.Object) error { + err = doc2.Update(func(root *json.Object, p *presence.Presence) error { text := root.SetNewText("k1") text.Edit(0, 0, builder.String()) return nil diff --git a/test/bench/text_editing_bench_test.go b/test/bench/text_editing_bench_test.go index 35dc74f23..6b91a45aa 100644 --- a/test/bench/text_editing_bench_test.go +++ b/test/bench/text_editing_bench_test.go @@ -28,6 +28,7 @@ import ( "github.com/yorkie-team/yorkie/pkg/document" "github.com/yorkie-team/yorkie/pkg/document/json" + "github.com/yorkie-team/yorkie/pkg/document/presence" ) func BenchmarkTextEditing(b *testing.B) { @@ -41,7 +42,7 @@ func BenchmarkTextEditing(b *testing.B) { b.StartTimer() doc := document.New("d1") - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewText("text") return nil }) @@ -50,7 +51,7 @@ func BenchmarkTextEditing(b *testing.B) { cursor := int(edit[0].(float64)) mode := int(edit[1].(float64)) - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { text := root.GetText("text") if mode == 0 { value := edit[2].(string) diff --git a/test/helper/helper.go b/test/helper/helper.go index b324d5f27..ba6c2da1f 100644 --- a/test/helper/helper.go +++ b/test/helper/helper.go @@ -34,6 +34,7 @@ import ( "github.com/yorkie-team/yorkie/pkg/document/crdt" "github.com/yorkie-team/yorkie/pkg/document/json" "github.com/yorkie-team/yorkie/pkg/document/key" + "github.com/yorkie-team/yorkie/pkg/document/presence" "github.com/yorkie-team/yorkie/pkg/document/time" "github.com/yorkie-team/yorkie/pkg/index" "github.com/yorkie-team/yorkie/server" @@ -177,7 +178,7 @@ func ToDiagnostic(node *crdt.TreeNode) string { // BuildIndexTree builds an index tree from the given block node. func BuildIndexTree(node *json.TreeNode) *index.Tree[*crdt.TreeNode] { doc := document.New("test") - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewTree("test", node) return nil @@ -192,7 +193,7 @@ func BuildIndexTree(node *json.TreeNode) *index.Tree[*crdt.TreeNode] { // BuildTreeNode builds a crdt.TreeNode from the given tree node. func BuildTreeNode(node *json.TreeNode) *crdt.TreeNode { doc := document.New("test") - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewTree("test", node) return nil @@ -230,6 +231,7 @@ func TestConfig() *server.Config { AdminTokenDuration: server.DefaultAdminTokenDuration.String(), UseDefaultProject: true, ClientDeactivateThreshold: server.DefaultClientDeactivateThreshold, + SnapshotInterval: 10, SnapshotThreshold: SnapshotThreshold, SnapshotWithPurgingChanges: SnapshotWithPurgingChanges, AuthWebhookMaxWaitInterval: AuthWebhookMaxWaitInterval.String(), diff --git a/test/integration/admin_test.go b/test/integration/admin_test.go index 695e783ee..cc3873baa 100644 --- a/test/integration/admin_test.go +++ b/test/integration/admin_test.go @@ -32,6 +32,7 @@ import ( "github.com/yorkie-team/yorkie/client" "github.com/yorkie-team/yorkie/pkg/document" "github.com/yorkie-team/yorkie/pkg/document/json" + "github.com/yorkie-team/yorkie/pkg/document/presence" "github.com/yorkie-team/yorkie/test/helper" ) @@ -73,7 +74,7 @@ func TestAdmin(t *testing.T) { assert.Equal(t, document.StatusAttached, d1.Status()) // 03. client updates the document and sync to the server. - assert.NoError(t, d1.Update(func(root *json.Object) error { + assert.NoError(t, d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetString("k1", "v1") return nil })) @@ -104,8 +105,8 @@ func TestAdmin(t *testing.T) { } assert.NoError(t, resp.Err) - if resp.Type == client.DocumentsChanged { - err := c1.Sync(ctx, client.WithDocKey(resp.Key)) + if resp.Type == client.DocumentChanged { + err := c1.Sync(ctx, client.WithDocKey(d1.Key())) assert.NoError(t, err) return } @@ -118,7 +119,7 @@ func TestAdmin(t *testing.T) { // 03. wait for watching document changed event. wg.Wait() - assert.Equal(t, d1.Status(), document.StatusRemoved) + assert.Equal(t, document.StatusRemoved, d1.Status()) }) t.Run("document removal without force test", func(t *testing.T) { @@ -143,7 +144,7 @@ func TestAdmin(t *testing.T) { assert.Equal(t, document.StatusAttached, doc.Status()) // 03. remove document that is detached by the client. - assert.NoError(t, cli.Detach(ctx, doc, false)) + assert.NoError(t, cli.Detach(ctx, doc)) err = adminCli.RemoveDocument(ctx, "default", doc.Key().String(), false) assert.NoError(t, err) assert.Equal(t, document.StatusDetached, doc.Status()) diff --git a/test/integration/agent_test.go b/test/integration/agent_test.go index 5b0138451..ebe9bfedc 100644 --- a/test/integration/agent_test.go +++ b/test/integration/agent_test.go @@ -58,8 +58,7 @@ func TestServer(t *testing.T) { return case wr := <-wrch: if wr.Err == io.EOF || status.Code(wr.Err) == codes.Canceled { - peers := wr.PeersMapByDoc[doc.Key()] - assert.Len(t, peers, 0) + assert.Len(t, wr.Presences, 0) wg.Done() return } diff --git a/test/integration/array_test.go b/test/integration/array_test.go index 5d8568ae0..90c992fcc 100644 --- a/test/integration/array_test.go +++ b/test/integration/array_test.go @@ -26,6 +26,7 @@ import ( "github.com/yorkie-team/yorkie/pkg/document" "github.com/yorkie-team/yorkie/pkg/document/json" + "github.com/yorkie-team/yorkie/pkg/document/presence" "github.com/yorkie-team/yorkie/test/helper" ) @@ -40,7 +41,7 @@ func TestArray(t *testing.T) { err := c1.Attach(ctx, d1) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewArray("k1"). AddString("v1"). AddNewArray().AddString("1", "2", "3") @@ -61,7 +62,7 @@ func TestArray(t *testing.T) { err := c1.Attach(ctx, d1) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewArray("k1").AddString("v1", "v2") return nil }, "add v1, v2 by c1") @@ -74,13 +75,13 @@ func TestArray(t *testing.T) { err = c2.Attach(ctx, d2) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.GetArray("k1").Delete(1) return nil }, "delete v2 by c1") assert.NoError(t, err) - err = d2.Update(func(root *json.Object) error { + err = d2.Update(func(root *json.Object, p *presence.Presence) error { root.GetArray("k1").AddString("v3") return nil }, "add v3 by c2") @@ -95,7 +96,7 @@ func TestArray(t *testing.T) { err := c1.Attach(ctx, d1) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewArray("k1").AddString("v1") return nil }, "new array and add v1") @@ -107,14 +108,14 @@ func TestArray(t *testing.T) { err = c2.Attach(ctx, d2) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.GetArray("k1").AddString("v2", "v3") root.GetArray("k1").Delete(1) return nil }, "add v2, v3 and delete v2 by c1") assert.NoError(t, err) - err = d2.Update(func(root *json.Object) error { + err = d2.Update(func(root *json.Object, p *presence.Presence) error { root.GetArray("k1").AddString("v4", "v5") return nil }, "add v4, v5 by c2") @@ -129,7 +130,7 @@ func TestArray(t *testing.T) { err := c1.Attach(ctx, d1) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewArray("k1").AddString("v1", "v2", "v3") return nil }, "new array and add v1 v2 v3") @@ -141,20 +142,20 @@ func TestArray(t *testing.T) { err = c2.Attach(ctx, d2) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.GetArray("k1").Delete(1) return nil }, "delete v2") assert.NoError(t, err) - err = d2.Update(func(root *json.Object) error { + err = d2.Update(func(root *json.Object, p *presence.Presence) error { root.GetArray("k1").Delete(1) return nil }, "delete v2") assert.NoError(t, err) syncClientsThenAssertEqual(t, []clientAndDocPair{{c1, d1}, {c2, d2}}) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { assert.Equal(t, 2, root.GetArray("k1").Len()) return nil }, "check array length") @@ -168,7 +169,7 @@ func TestArray(t *testing.T) { err := c1.Attach(ctx, d1) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewArray("k1").AddInteger(0, 1, 2) assert.Equal(t, `{"k1":[0,1,2]}`, root.Marshal()) return nil @@ -181,7 +182,7 @@ func TestArray(t *testing.T) { err = c2.Attach(ctx, d2) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { prev := root.GetArray("k1").Get(0) elem := root.GetArray("k1").Get(2) root.GetArray("k1").MoveBefore(prev.CreatedAt(), elem.CreatedAt()) @@ -190,7 +191,7 @@ func TestArray(t *testing.T) { }, "move 2 before 0") assert.NoError(t, err) - err = d2.Update(func(root *json.Object) error { + err = d2.Update(func(root *json.Object, p *presence.Presence) error { prev := root.GetArray("k1").Get(1) elem := root.GetArray("k1").Get(2) root.GetArray("k1").MoveBefore(prev.CreatedAt(), elem.CreatedAt()) @@ -206,7 +207,7 @@ func TestArray(t *testing.T) { ctx := context.Background() d1 := document.New(helper.TestDocKey(t)) assert.NoError(t, c1.Attach(ctx, d1)) - assert.NoError(t, d1.Update(func(root *json.Object) error { + assert.NoError(t, d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewArray("k1").AddInteger(0, 1, 2) assert.Equal(t, `{"k1":[0,1,2]}`, root.Marshal()) return nil @@ -215,7 +216,7 @@ func TestArray(t *testing.T) { d2 := document.New(helper.TestDocKey(t)) assert.NoError(t, c2.Attach(ctx, d2)) - assert.NoError(t, d1.Update(func(root *json.Object) error { + assert.NoError(t, d1.Update(func(root *json.Object, p *presence.Presence) error { next := root.GetArray("k1").Get(0) elem := root.GetArray("k1").Get(2) root.GetArray("k1").MoveBefore(next.CreatedAt(), elem.CreatedAt()) @@ -223,7 +224,7 @@ func TestArray(t *testing.T) { return nil })) - assert.NoError(t, d2.Update(func(root *json.Object) error { + assert.NoError(t, d2.Update(func(root *json.Object, p *presence.Presence) error { next := root.GetArray("k1").Get(0) elem := root.GetArray("k1").Get(1) root.GetArray("k1").MoveBefore(next.CreatedAt(), elem.CreatedAt()) diff --git a/test/integration/auth_webhook_test.go b/test/integration/auth_webhook_test.go index 0c5651788..f5bb1aa5b 100644 --- a/test/integration/auth_webhook_test.go +++ b/test/integration/auth_webhook_test.go @@ -34,6 +34,7 @@ import ( "github.com/yorkie-team/yorkie/client" "github.com/yorkie-team/yorkie/pkg/document" "github.com/yorkie-team/yorkie/pkg/document/json" + "github.com/yorkie-team/yorkie/pkg/document/presence" "github.com/yorkie-team/yorkie/server" "github.com/yorkie-team/yorkie/test/helper" ) @@ -322,7 +323,7 @@ func TestAuthWebhook(t *testing.T) { // 01. multiple requests to update the document. for i := 0; i < 3; i++ { - assert.NoError(t, doc.Update(func(root *json.Object) error { + assert.NoError(t, doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewObject("k1") return nil })) @@ -332,7 +333,7 @@ func TestAuthWebhook(t *testing.T) { // 02. multiple requests to update the document after eviction by ttl. time.Sleep(authorizedTTL) for i := 0; i < 3; i++ { - assert.NoError(t, doc.Update(func(root *json.Object) error { + assert.NoError(t, doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewObject("k1") return nil })) diff --git a/test/integration/client_test.go b/test/integration/client_test.go index 3c6a96da3..e37fe4413 100644 --- a/test/integration/client_test.go +++ b/test/integration/client_test.go @@ -29,6 +29,7 @@ import ( "github.com/yorkie-team/yorkie/pkg/document/change" "github.com/yorkie-team/yorkie/pkg/document/crdt" "github.com/yorkie-team/yorkie/pkg/document/json" + "github.com/yorkie-team/yorkie/pkg/document/presence" "github.com/yorkie-team/yorkie/test/helper" ) @@ -88,11 +89,11 @@ func TestClient(t *testing.T) { assert.NoError(t, c3.Attach(ctx, d3)) // 02. c1, c2 sync with push-pull mode. - assert.NoError(t, d1.Update(func(root *json.Object) error { + assert.NoError(t, d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetInteger("c1", 0) return nil })) - assert.NoError(t, d1.Update(func(root *json.Object) error { + assert.NoError(t, d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetInteger("c2", 0) return nil })) @@ -104,11 +105,11 @@ func TestClient(t *testing.T) { // 03. c1 and c2 sync with push-only mode. So, the changes of c1 and c2 // are not reflected to each other. // But, c3 can get the changes of c1 and c2, because c3 sync with pull-pull mode. - assert.NoError(t, d1.Update(func(root *json.Object) error { + assert.NoError(t, d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetInteger("c1", 1) return nil })) - assert.NoError(t, d2.Update(func(root *json.Object) error { + assert.NoError(t, d2.Update(func(root *json.Object, p *presence.Presence) error { root.SetInteger("c2", 1) return nil })) @@ -138,28 +139,28 @@ func TestClient(t *testing.T) { assert.NoError(t, cli.Attach(ctx, doc)) // 02. cli update the document with creating a counter - // and sync with push-pull mode: CP(0, 0) -> CP(1, 1) - assert.NoError(t, doc.Update(func(root *json.Object) error { + // and sync with push-pull mode: CP(1, 1) -> CP(2, 2) + assert.NoError(t, doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewCounter("counter", crdt.IntegerCnt, 0) return nil })) - assert.Equal(t, change.Checkpoint{ClientSeq: 0, ServerSeq: 0}, doc.Checkpoint()) + assert.Equal(t, change.Checkpoint{ClientSeq: 1, ServerSeq: 1}, doc.Checkpoint()) assert.NoError(t, cli.Sync(ctx, client.WithDocKey(doc.Key()))) - assert.Equal(t, doc.Checkpoint(), change.Checkpoint{ClientSeq: 1, ServerSeq: 1}) + assert.Equal(t, doc.Checkpoint(), change.Checkpoint{ClientSeq: 2, ServerSeq: 2}) // 03. cli update the document with increasing the counter(0 -> 1) - // and sync with push-only mode: CP(1, 1) -> CP(2, 1) - assert.NoError(t, doc.Update(func(root *json.Object) error { + // and sync with push-only mode: CP(2, 2) -> CP(3, 2) + assert.NoError(t, doc.Update(func(root *json.Object, p *presence.Presence) error { root.GetCounter("counter").Increase(1) return nil })) assert.Len(t, doc.CreateChangePack().Changes, 1) assert.NoError(t, cli.Sync(ctx, client.WithDocKey(doc.Key()).WithPushOnly())) - assert.Equal(t, doc.Checkpoint(), change.Checkpoint{ClientSeq: 2, ServerSeq: 1}) + assert.Equal(t, doc.Checkpoint(), change.Checkpoint{ClientSeq: 3, ServerSeq: 2}) // 04. cli update the document with increasing the counter(1 -> 2) - // and sync with push-pull mode. CP(2, 1) -> CP(3, 3) - assert.NoError(t, doc.Update(func(root *json.Object) error { + // and sync with push-pull mode. CP(3, 2) -> CP(4, 4) + assert.NoError(t, doc.Update(func(root *json.Object, p *presence.Presence) error { root.GetCounter("counter").Increase(1) return nil })) @@ -168,7 +169,7 @@ func TestClient(t *testing.T) { // so the ChangePack of the request only has the increase(1 -> 2). assert.Len(t, doc.CreateChangePack().Changes, 1) assert.NoError(t, cli.Sync(ctx, client.WithDocKey(doc.Key()))) - assert.Equal(t, doc.Checkpoint(), change.Checkpoint{ClientSeq: 3, ServerSeq: 3}) + assert.Equal(t, doc.Checkpoint(), change.Checkpoint{ClientSeq: 4, ServerSeq: 4}) assert.Equal(t, "2", doc.Root().GetCounter("counter").Marshal()) }) } diff --git a/test/integration/counter_test.go b/test/integration/counter_test.go index 06c601581..4971c88e5 100644 --- a/test/integration/counter_test.go +++ b/test/integration/counter_test.go @@ -28,6 +28,7 @@ import ( "github.com/yorkie-team/yorkie/pkg/document" "github.com/yorkie-team/yorkie/pkg/document/crdt" "github.com/yorkie-team/yorkie/pkg/document/json" + "github.com/yorkie-team/yorkie/pkg/document/presence" "github.com/yorkie-team/yorkie/test/helper" ) @@ -42,7 +43,7 @@ func TestCounter(t *testing.T) { err := c1.Attach(ctx, d1) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewCounter("age", crdt.LongCnt, 1). Increase(2). Increase(2.5). @@ -66,7 +67,7 @@ func TestCounter(t *testing.T) { err := c1.Attach(ctx, d1) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewCounter("age", crdt.IntegerCnt, 0) root.SetNewCounter("width", crdt.LongCnt, 0) root.SetNewCounter("height", crdt.LongCnt, 0) @@ -80,7 +81,7 @@ func TestCounter(t *testing.T) { err = c2.Attach(ctx, d2) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.GetCounter("age"). Increase(1). Increase(2). @@ -90,13 +91,13 @@ func TestCounter(t *testing.T) { }) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.GetCounter("width").Increase(math.MaxInt32 + 100).Increase(10) return nil }) assert.NoError(t, err) - err = d2.Update(func(root *json.Object) error { + err = d2.Update(func(root *json.Object, p *presence.Presence) error { root.GetCounter("age").Increase(20) root.GetCounter("width").Increase(100).Increase(200) root.GetCounter("height").Increase(50) diff --git a/test/integration/document_test.go b/test/integration/document_test.go index 15b2dbffc..2a5981c3d 100644 --- a/test/integration/document_test.go +++ b/test/integration/document_test.go @@ -26,11 +26,12 @@ import ( "github.com/stretchr/testify/assert" - "github.com/yorkie-team/yorkie/api/types" "github.com/yorkie-team/yorkie/client" "github.com/yorkie-team/yorkie/pkg/document" + "github.com/yorkie-team/yorkie/pkg/document/innerpresence" "github.com/yorkie-team/yorkie/pkg/document/json" "github.com/yorkie-team/yorkie/pkg/document/key" + "github.com/yorkie-team/yorkie/pkg/document/presence" "github.com/yorkie-team/yorkie/test/helper" ) @@ -42,7 +43,7 @@ func TestDocument(t *testing.T) { t.Run("attach/detach test", func(t *testing.T) { ctx := context.Background() doc := document.New(helper.TestDocKey(t)) - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetString("k1", "v1") return nil }, "update k1 with v1") @@ -52,12 +53,12 @@ func TestDocument(t *testing.T) { assert.NoError(t, err) assert.True(t, doc.IsAttached()) - err = c1.Detach(ctx, doc, false) + err = c1.Detach(ctx, doc) assert.NoError(t, err) assert.False(t, doc.IsAttached()) doc2 := document.New(helper.TestDocKey(t)) - err = doc2.Update(func(root *json.Object) error { + err = doc2.Update(func(root *json.Object, p *presence.Presence) error { root.SetString("k1", "v2") return nil }, "update k1 with v2") @@ -76,7 +77,7 @@ func TestDocument(t *testing.T) { // 01. create a document and attach it to c1 ctx := context.Background() doc := document.New(helper.TestDocKey(t)) - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetString("k1", "v1") return nil }, "update k1 with v1") @@ -87,7 +88,7 @@ func TestDocument(t *testing.T) { assert.True(t, doc.IsAttached()) // 02. detach with removeIfNotAttached option false - err = c1.Detach(ctx, doc, false) + err = c1.Detach(ctx, doc) assert.NoError(t, err) assert.False(t, doc.IsAttached()) assert.Equal(t, doc.Status(), document.StatusDetached) @@ -98,7 +99,7 @@ func TestDocument(t *testing.T) { assert.True(t, doc.IsAttached()) // 04. detach with removeIfNotAttached option true - err = c1.Detach(ctx, doc, true) + err = c1.Detach(ctx, doc, client.WithRemoveIfNotAttached()) assert.NoError(t, err) assert.False(t, doc.IsAttached()) assert.Equal(t, doc.Status(), document.StatusRemoved) @@ -114,26 +115,26 @@ func TestDocument(t *testing.T) { err = c2.Attach(ctx, d2) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewObject("k1").SetNewArray("k1.1").AddString("1", "2") return nil }) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewArray("k2").AddString("1", "2", "3") return nil }) assert.NoError(t, err) - err = d2.Update(func(root *json.Object) error { + err = d2.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewArray("k1").AddString("4", "5") root.SetNewArray("k2").AddString("6", "7") return nil }) assert.NoError(t, err) - err = d2.Update(func(root *json.Object) error { + err = d2.Update(func(root *json.Object, p *presence.Presence) error { root.Delete("k2") return nil }) @@ -173,8 +174,8 @@ func TestDocument(t *testing.T) { } assert.NoError(t, resp.Err) - if resp.Type == client.DocumentsChanged { - err := c1.Sync(ctx, client.WithDocKey(resp.Key)) + if resp.Type == client.DocumentChanged { + err := c1.Sync(ctx, client.WithDocKey(d1.Key())) assert.NoError(t, err) return } @@ -182,7 +183,7 @@ func TestDocument(t *testing.T) { }() // 02. cli2 updates doc2. - err = d2.Update(func(root *json.Object) error { + err = d2.Update(func(root *json.Object, p *presence.Presence) error { root.SetString("key", "value") return nil }) @@ -200,7 +201,7 @@ func TestDocument(t *testing.T) { ctx := context.Background() d1 := document.New(helper.TestDocKey(t)) - err := d1.Update(func(root *json.Object) error { + err := d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewArray("k1").AddInteger(1, 2) return nil }) @@ -215,7 +216,7 @@ func TestDocument(t *testing.T) { syncClientsThenAssertEqual(t, []clientAndDocPair{{c1, d1}, {c2, d2}}) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.GetArray("k1").AddInteger(3) return nil }) @@ -224,7 +225,7 @@ func TestDocument(t *testing.T) { prevArray := d1.Root().Get("k1") assert.Nil(t, prevArray.RemovedAt()) - err = d2.Update(func(root *json.Object) error { + err = d2.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewArray("k1") return nil }) @@ -257,7 +258,7 @@ func TestDocument(t *testing.T) { assert.Equal(t, document.StatusRemoved, d1.Status()) // 04. try to update a removed document. - assert.ErrorIs(t, d1.Update(func(root *json.Object) error { + assert.ErrorIs(t, d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetString("k1", "v1") return nil }), document.ErrDocumentRemoved) @@ -271,7 +272,7 @@ func TestDocument(t *testing.T) { // 01. cli1 creates d1 and removes it. d1 := document.New(helper.TestDocKey(t)) - err := d1.Update(func(root *json.Object) error { + err := d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetString("k1", "v1") return nil }) @@ -294,7 +295,7 @@ func TestDocument(t *testing.T) { // 01. cli1 creates d1 and cli2 syncs. d1 := document.New(helper.TestDocKey(t)) - err := d1.Update(func(root *json.Object) error { + err := d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetString("k1", "v1") return nil }) @@ -306,7 +307,7 @@ func TestDocument(t *testing.T) { syncClientsThenAssertEqual(t, []clientAndDocPair{{c1, d1}, {c2, d2}}) // 02. cli1 updates d1 and removes it. - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetString("k1", "v2") return nil }) @@ -325,7 +326,7 @@ func TestDocument(t *testing.T) { // 01. cli1 creates d1 and cli2 syncs. d1 := document.New(helper.TestDocKey(t)) - err := d1.Update(func(root *json.Object) error { + err := d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetString("k1", "v1") return nil }) @@ -337,7 +338,7 @@ func TestDocument(t *testing.T) { // 02. cli1 removes d1 and cli2 detaches d2. assert.NoError(t, c1.Remove(ctx, d1)) - assert.NoError(t, c2.Detach(ctx, d2, false)) + assert.NoError(t, c2.Detach(ctx, d2)) assert.Equal(t, d1.Status(), document.StatusRemoved) assert.Equal(t, d2.Status(), document.StatusRemoved) }) @@ -347,7 +348,7 @@ func TestDocument(t *testing.T) { // 01. cli1 creates d1 and cli2 syncs. d1 := document.New(helper.TestDocKey(t)) - err := d1.Update(func(root *json.Object) error { + err := d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetString("k1", "v1") return nil }) @@ -382,7 +383,7 @@ func TestDocument(t *testing.T) { // 01. abnormal behavior on detached state d1 := document.New(helper.TestDocKey(t)) - assert.ErrorIs(t, cli.Detach(ctx, d1, false), client.ErrDocumentNotAttached) + assert.ErrorIs(t, cli.Detach(ctx, d1), client.ErrDocumentNotAttached) assert.ErrorIs(t, cli.Sync(ctx, client.WithDocKey(d1.Key())), client.ErrDocumentNotAttached) assert.ErrorIs(t, cli.Remove(ctx, d1), client.ErrDocumentNotAttached) @@ -394,7 +395,7 @@ func TestDocument(t *testing.T) { assert.NoError(t, cli.Remove(ctx, d1)) assert.ErrorIs(t, cli.Remove(ctx, d1), client.ErrDocumentNotAttached) assert.ErrorIs(t, cli.Sync(ctx, client.WithDocKey(d1.Key())), client.ErrDocumentNotAttached) - assert.ErrorIs(t, cli.Detach(ctx, d1, false), client.ErrDocumentNotAttached) + assert.ErrorIs(t, cli.Detach(ctx, d1), client.ErrDocumentNotAttached) }) t.Run("removed document removal with watching test", func(t *testing.T) { @@ -469,7 +470,6 @@ func TestDocumentWithProjects(t *testing.T) { go func() { defer wg.Done() - for { resp := <-rch if resp.Err == io.EOF { @@ -478,62 +478,62 @@ func TestDocumentWithProjects(t *testing.T) { } assert.NoError(t, resp.Err) - if resp.Type == client.DocumentsChanged { - err := c1.Sync(ctx, client.WithDocKey(resp.Key)) + if resp.Type == client.DocumentChanged { + err := c1.Sync(ctx, client.WithDocKey(d1.Key())) assert.NoError(t, err) + } else { responsePairs = append(responsePairs, watchResponsePair{ - Type: resp.Type, + Type: resp.Type, + Presences: resp.Presences, }) - return } - - if resp.Type == client.PeersChanged { - peers := resp.PeersMapByDoc[d1.Key()] - responsePairs = append(responsePairs, watchResponsePair{ - Type: resp.Type, - Peers: peers, - }) + if len(responsePairs) == 2 { + return } } }() - // c2 watches the same document, so c1 receives a peers changed event. + // c2 watches the same document, so c1 receives a document watched event. expected = append(expected, watchResponsePair{ - Type: client.PeersChanged, - Peers: map[string]types.Presence{ - c1.ID().String(): nil, - c2.ID().String(): nil, + Type: client.DocumentWatched, + Presences: map[string]innerpresence.Presence{ + c2.ID().String(): {}, }, }) d2 := document.New(helper.TestDocKey(t)) assert.NoError(t, c2.Attach(ctx, d2)) watch2Ctx, cancel2 := context.WithCancel(ctx) - defer cancel2() _, err = c2.Watch(watch2Ctx, d2) assert.NoError(t, err) // c2 updates the document, so c1 receives a documents changed event. - expected = append(expected, watchResponsePair{ - Type: client.DocumentsChanged, - }) - assert.NoError(t, d2.Update(func(root *json.Object) error { + assert.NoError(t, d2.Update(func(root *json.Object, p *presence.Presence) error { root.SetString("key", "value") return nil })) + assert.NoError(t, c2.Sync(ctx)) // d3 is in another project, so c1 and c2 should not receive events. d3 := document.New(helper.TestDocKey(t)) assert.NoError(t, c3.Attach(ctx, d3)) watch3Ctx, cancel3 := context.WithCancel(ctx) - defer cancel3() _, err = c3.Watch(watch3Ctx, d3) assert.NoError(t, err) - assert.NoError(t, d3.Update(func(root *json.Object) error { + assert.NoError(t, d3.Update(func(root *json.Object, p *presence.Presence) error { root.SetString("key3", "value3") return nil })) - assert.NoError(t, c2.Sync(ctx)) + assert.NoError(t, c3.Sync(ctx)) + // c2 unwatch the document, so c1 receives a document unwatched event. + expected = append(expected, watchResponsePair{ + Type: client.DocumentUnwatched, + Presences: map[string]innerpresence.Presence{ + c2.ID().String(): {}, + }, + }) + cancel3() + cancel2() wg.Wait() assert.Equal(t, expected, responsePairs) @@ -549,9 +549,9 @@ func TestDocumentWithProjects(t *testing.T) { t.Run("includeSnapshot test", func(t *testing.T) { d1 := document.New(helper.TestDocKey(t)) assert.NoError(t, cli.Attach(ctx, d1)) - defer func() { assert.NoError(t, cli.Detach(ctx, d1, false)) }() + defer func() { assert.NoError(t, cli.Detach(ctx, d1)) }() - assert.NoError(t, d1.Update(func(root *json.Object) error { + assert.NoError(t, d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewArray("testArray") return nil }, "add test array")) diff --git a/test/integration/gc_test.go b/test/integration/gc_test.go index d425f2b23..907973820 100644 --- a/test/integration/gc_test.go +++ b/test/integration/gc_test.go @@ -26,6 +26,7 @@ import ( "github.com/yorkie-team/yorkie/pkg/document" "github.com/yorkie-team/yorkie/pkg/document/json" + "github.com/yorkie-team/yorkie/pkg/document/presence" "github.com/yorkie-team/yorkie/pkg/document/time" "github.com/yorkie-team/yorkie/test/helper" ) @@ -45,7 +46,7 @@ func TestGarbageCollection(t *testing.T) { err = c2.Attach(ctx, d2) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetInteger("1", 1) root.SetNewArray("2").AddInteger(1, 2, 3) root.SetInteger("3", 3) @@ -63,7 +64,7 @@ func TestGarbageCollection(t *testing.T) { err = c2.Sync(ctx) assert.NoError(t, err) - err = d2.Update(func(root *json.Object) error { + err = d2.Update(func(root *json.Object, p *presence.Presence) error { root.Delete("2") return nil }, "removes 2") @@ -112,7 +113,7 @@ func TestGarbageCollection(t *testing.T) { err = c2.Attach(ctx, d2) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewText("text"). Edit(0, 0, "Hello world") root.SetNewText("richText"). @@ -131,7 +132,7 @@ func TestGarbageCollection(t *testing.T) { err = c2.Sync(ctx) assert.NoError(t, err) - err = d2.Update(func(root *json.Object) error { + err = d2.Update(func(root *json.Object, p *presence.Presence) error { root.GetText("text"). Edit(0, 1, "a"). Edit(1, 2, "b") @@ -177,7 +178,7 @@ func TestGarbageCollection(t *testing.T) { t.Run("garbage collection for tree type test", func(t *testing.T) { doc := document.New(helper.TestDocKey(t)) - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewTree("t", &json.TreeNode{ Type: "doc", Children: []json.TreeNode{{ @@ -200,7 +201,7 @@ func TestGarbageCollection(t *testing.T) { }) assert.NoError(t, err) - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { root.GetTree("t").EditByPath([]int{0, 0, 0}, []int{0, 0, 2}, &json.TreeNode{Type: "text", Value: "gh"}) assert.Equal(t, `

ghcd

`, root.GetTree("t").ToXML()) return nil @@ -212,7 +213,7 @@ func TestGarbageCollection(t *testing.T) { assert.Equal(t, doc.GarbageCollect(time.MaxTicket), 2) assert.Equal(t, doc.GarbageLen(), 0) - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { root.GetTree("t").EditByPath([]int{0, 0, 0}, []int{0, 0, 2}, &json.TreeNode{Type: "text", Value: "cv"}) assert.Equal(t, `

cvcd

`, root.GetTree("t").ToXML()) return nil @@ -224,7 +225,7 @@ func TestGarbageCollection(t *testing.T) { assert.Equal(t, doc.GarbageCollect(time.MaxTicket), 1) assert.Equal(t, doc.GarbageLen(), 0) - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { root.GetTree("t").EditByPath([]int{0}, []int{1}, &json.TreeNode{ Type: "p", Children: []json.TreeNode{{ Type: "tn", Children: []json.TreeNode{{ @@ -252,7 +253,7 @@ func TestGarbageCollection(t *testing.T) { err = c2.Attach(ctx, d2) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewTree("t", &json.TreeNode{ Type: "doc", Children: []json.TreeNode{{ @@ -281,7 +282,7 @@ func TestGarbageCollection(t *testing.T) { err = c2.Sync(ctx) assert.NoError(t, err) - err = d2.Update(func(root *json.Object) error { + err = d2.Update(func(root *json.Object, p *presence.Presence) error { root.GetTree("t").EditByPath([]int{0, 0, 0}, []int{0, 0, 2}, &json.TreeNode{Type: "text", Value: "gh"}) return nil }) @@ -330,7 +331,7 @@ func TestGarbageCollection(t *testing.T) { err = c2.Attach(ctx, d2) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetInteger("1", 1) root.SetNewArray("2").AddInteger(1, 2, 3) root.SetInteger("3", 3) @@ -350,7 +351,7 @@ func TestGarbageCollection(t *testing.T) { err = c2.Sync(ctx) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.Delete("2") root.GetText("4").Edit(0, 1, "h") root.GetText("5").Edit(0, 1, "h", map[string]string{"b": "1"}) @@ -366,7 +367,7 @@ func TestGarbageCollection(t *testing.T) { assert.Equal(t, 6, d1.GarbageLen()) assert.Equal(t, 0, d2.GarbageLen()) - err = c2.Detach(ctx, d2, false) + err = c2.Detach(ctx, d2) assert.NoError(t, err) // (2, 1) -> (2, 2): syncedseqs:(1, x) diff --git a/test/integration/history_test.go b/test/integration/history_test.go index b03446da2..24134ab06 100644 --- a/test/integration/history_test.go +++ b/test/integration/history_test.go @@ -26,6 +26,7 @@ import ( "github.com/yorkie-team/yorkie/pkg/document" "github.com/yorkie-team/yorkie/pkg/document/json" + "github.com/yorkie-team/yorkie/pkg/document/presence" "github.com/yorkie-team/yorkie/test/helper" ) @@ -41,21 +42,21 @@ func TestHistory(t *testing.T) { ctx := context.Background() d1 := document.New(helper.TestDocKey(t)) assert.NoError(t, cli.Attach(ctx, d1)) - defer func() { assert.NoError(t, cli.Detach(ctx, d1, false)) }() + defer func() { assert.NoError(t, cli.Detach(ctx, d1)) }() - assert.NoError(t, d1.Update(func(root *json.Object) error { + assert.NoError(t, d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewArray("todos") return nil }, "create todos")) assert.Equal(t, `{"todos":[]}`, d1.Marshal()) - assert.NoError(t, d1.Update(func(root *json.Object) error { + assert.NoError(t, d1.Update(func(root *json.Object, p *presence.Presence) error { root.GetArray("todos").AddString("buy coffee") return nil }, "buy coffee")) assert.Equal(t, `{"todos":["buy coffee"]}`, d1.Marshal()) - assert.NoError(t, d1.Update(func(root *json.Object) error { + assert.NoError(t, d1.Update(func(root *json.Object, p *presence.Presence) error { root.GetArray("todos").AddString("buy bread") return nil }, "buy bread")) @@ -64,7 +65,8 @@ func TestHistory(t *testing.T) { changes, err := adminCli.ListChangeSummaries(ctx, "default", d1.Key(), 0, 0, true) assert.NoError(t, err) - assert.Len(t, changes, 3) + // NOTE(chacha912): When attaching, a change is made to set the initial presence. + assert.Len(t, changes, 4) assert.Equal(t, "create todos", changes[2].Message) assert.Equal(t, "buy coffee", changes[1].Message) diff --git a/test/integration/main_test.go b/test/integration/main_test.go index e217e6e7d..fc49bb486 100644 --- a/test/integration/main_test.go +++ b/test/integration/main_test.go @@ -28,9 +28,9 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" - "github.com/yorkie-team/yorkie/api/types" "github.com/yorkie-team/yorkie/client" "github.com/yorkie-team/yorkie/pkg/document" + "github.com/yorkie-team/yorkie/pkg/document/innerpresence" "github.com/yorkie-team/yorkie/server" "github.com/yorkie-team/yorkie/server/logging" "github.com/yorkie-team/yorkie/test/helper" @@ -42,8 +42,8 @@ type clientAndDocPair struct { } type watchResponsePair struct { - Type client.WatchResponseType - Peers map[string]types.Presence + Type client.WatchResponseType + Presences map[string]innerpresence.Presence } var defaultServer *server.Yorkie @@ -106,10 +106,7 @@ func clientConn() (*grpc.ClientConn, error) { // activeClients creates and activates the given number of clients. func activeClients(t *testing.T, n int) (clients []*client.Client) { for i := 0; i < n; i++ { - c, err := client.Dial( - defaultServer.RPCAddr(), - client.WithPresence(types.Presence{"name": fmt.Sprintf("name-%d", i)}), - ) + c, err := client.Dial(defaultServer.RPCAddr()) assert.NoError(t, err) assert.NoError(t, c.Activate(context.Background())) diff --git a/test/integration/object_test.go b/test/integration/object_test.go index 33a158c3c..da1e95275 100644 --- a/test/integration/object_test.go +++ b/test/integration/object_test.go @@ -26,6 +26,7 @@ import ( "github.com/yorkie-team/yorkie/pkg/document" "github.com/yorkie-team/yorkie/pkg/document/json" + "github.com/yorkie-team/yorkie/pkg/document/presence" "github.com/yorkie-team/yorkie/test/helper" ) @@ -45,7 +46,7 @@ func TestObject(t *testing.T) { err = c2.Attach(ctx, d2) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewObject("k1"). SetString("k1.1", "v1"). SetString("k1.2", "v2"). @@ -59,7 +60,7 @@ func TestObject(t *testing.T) { assert.NoError(t, err) syncClientsThenAssertEqual(t, []clientAndDocPair{{c1, d1}, {c2, d2}}) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.Delete("k1") root.GetObject("k2").Delete("k2.2") return nil @@ -74,7 +75,7 @@ func TestObject(t *testing.T) { err := c1.Attach(ctx, d1) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewObject("k1") return nil }, "set v1 by c1") @@ -87,7 +88,7 @@ func TestObject(t *testing.T) { err = c2.Attach(ctx, d2) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.Delete("k1") root.SetString("k1", "v1") return nil @@ -95,7 +96,7 @@ func TestObject(t *testing.T) { assert.NoError(t, err) assert.Equal(t, `{"k1":"v1"}`, d1.Marshal()) - err = d2.Update(func(root *json.Object) error { + err = d2.Update(func(root *json.Object, p *presence.Presence) error { root.Delete("k1") root.SetString("k1", "v2") return nil @@ -116,12 +117,12 @@ func TestObject(t *testing.T) { assert.NoError(t, err) // 01. concurrent set on same key - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetString("k1", "v1") return nil }, "set k1 by c1") assert.NoError(t, err) - err = d2.Update(func(root *json.Object) error { + err = d2.Update(func(root *json.Object, p *presence.Presence) error { root.SetString("k1", "v2") return nil }, "set k1 by c2") @@ -129,19 +130,19 @@ func TestObject(t *testing.T) { syncClientsThenAssertEqual(t, []clientAndDocPair{{c1, d1}, {c2, d2}}) // 02. concurrent set between ancestor descendant - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewObject("k2") return nil }, "set k2 by c1") assert.NoError(t, err) syncClientsThenAssertEqual(t, []clientAndDocPair{{c1, d1}, {c2, d2}}) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetString("k2", "v2") return nil }, "set k2 by c1") assert.NoError(t, err) - err = d2.Update(func(root *json.Object) error { + err = d2.Update(func(root *json.Object, p *presence.Presence) error { root.GetObject("k2").SetNewObject("k2.1").SetString("k2.1.1", "v2") return nil }, "set k2.1.1 by c2") @@ -149,12 +150,12 @@ func TestObject(t *testing.T) { syncClientsThenAssertEqual(t, []clientAndDocPair{{c1, d1}, {c2, d2}}) // 03. concurrent set between independent keys - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetString("k3", "v3") return nil }, "set k3 by c1") assert.NoError(t, err) - err = d2.Update(func(root *json.Object) error { + err = d2.Update(func(root *json.Object, p *presence.Presence) error { root.SetString("k4", "v4") return nil }, "set k4 by c2") diff --git a/test/integration/peer_awareness_test.go b/test/integration/peer_awareness_test.go deleted file mode 100644 index 316d52e22..000000000 --- a/test/integration/peer_awareness_test.go +++ /dev/null @@ -1,210 +0,0 @@ -//go:build integration - -/* - * Copyright 2021 The Yorkie Authors. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package integration - -import ( - "context" - "sync" - "testing" - "time" - - "github.com/stretchr/testify/assert" - - "github.com/yorkie-team/yorkie/api/types" - "github.com/yorkie-team/yorkie/client" - "github.com/yorkie-team/yorkie/pkg/document" - "github.com/yorkie-team/yorkie/pkg/document/key" - "github.com/yorkie-team/yorkie/test/helper" -) - -func TestPeerAwareness(t *testing.T) { - clients := activeClients(t, 2) - c1, c2 := clients[0], clients[1] - defer deactivateAndCloseClients(t, clients) - - t.Run("WatchStarted and PeersChanged event test", func(t *testing.T) { - ctx := context.Background() - d1 := document.New(helper.TestDocKey(t)) - d2 := document.New(helper.TestDocKey(t)) - assert.NoError(t, c1.Attach(ctx, d1)) - defer func() { assert.NoError(t, c1.Detach(ctx, d1, false)) }() - assert.NoError(t, c2.Attach(ctx, d2)) - defer func() { assert.NoError(t, c2.Detach(ctx, d2, false)) }() - - var expected []watchResponsePair - var responsePairs []watchResponsePair - wgEvents := sync.WaitGroup{} - wgEvents.Add(1) - - // starting to watch a document - watch1Ctx, cancel1 := context.WithCancel(ctx) - defer cancel1() - wrch, err := c1.Watch(watch1Ctx, d1) - assert.NoError(t, err) - go func() { - defer func() { - wgEvents.Done() - }() - for { - select { - case <-time.After(time.Second): - assert.Fail(t, "timeout") - return - case wr := <-wrch: - if wr.Err != nil { - assert.Fail(t, "unexpected stream closing", wr.Err) - return - } - - if wr.Type == client.PeersChanged { - peers := wr.PeersMapByDoc[d1.Key()] - responsePairs = append(responsePairs, watchResponsePair{ - Type: wr.Type, - Peers: peers, - }) - - if len(peers) == 1 { - return - } - } - } - } - }() - - // 01. PeersChanged is triggered when another client watches the document - expected = append(expected, watchResponsePair{ - Type: client.PeersChanged, - Peers: map[string]types.Presence{ - c1.ID().String(): c1.Presence(), - c2.ID().String(): c2.Presence(), - }, - }) - watch2Ctx, cancel2 := context.WithCancel(ctx) - _, err = c2.Watch(watch2Ctx, d2) - assert.NoError(t, err) - - // 02. PeersChanged is triggered when another client updates its presence - assert.NoError(t, c2.UpdatePresence(ctx, "updated", "true")) - expected = append(expected, watchResponsePair{ - Type: client.PeersChanged, - Peers: map[string]types.Presence{ - c1.ID().String(): c1.Presence(), - c2.ID().String(): c2.Presence(), - }, - }) - - // 03. PeersChanged is triggered when another client closes the watch - expected = append(expected, watchResponsePair{ - Type: client.PeersChanged, - Peers: map[string]types.Presence{ - c1.ID().String(): c1.Presence(), - }, - }) - cancel2() - - wgEvents.Wait() - - assert.Equal(t, expected, responsePairs) - }) - - t.Run("Watch multiple documents test", func(t *testing.T) { - ctx := context.Background() - - d1 := document.New(helper.TestDocKey(t)) - d2 := document.New(helper.TestDocKey(t)) - d3 := document.New(key.Key(helper.TestDocKey(t) + "2")) - assert.NoError(t, c1.Attach(ctx, d1)) - defer func() { assert.NoError(t, c1.Detach(ctx, d1, false)) }() - - var expected []watchResponsePair - var responsePairs []watchResponsePair - wgEvents := sync.WaitGroup{} - wgEvents.Add(1) - - // starting to watch a document - watch1Ctx, cancel1 := context.WithCancel(ctx) - defer cancel1() - wrch, err := c1.Watch(watch1Ctx, d1) - assert.NoError(t, err) - go func() { - defer func() { - wgEvents.Done() - }() - for { - select { - case <-time.After(time.Second): - assert.Fail(t, "timeout") - return - case wr := <-wrch: - if wr.Err != nil { - assert.Fail(t, "unexpected stream closing", wr.Err) - return - } - - if wr.Type == client.PeersChanged { - peers := wr.PeersMapByDoc[d1.Key()] - responsePairs = append(responsePairs, watchResponsePair{ - Type: wr.Type, - Peers: peers, - }) - - if len(peers) == 1 { - return - } - } - } - } - }() - - // 01. PeersChanged is triggered when another client watches the document - expected = append(expected, watchResponsePair{ - Type: client.PeersChanged, - Peers: map[string]types.Presence{ - c1.ID().String(): c1.Presence(), - c2.ID().String(): c2.Presence(), - }, - }) - assert.NoError(t, c2.Attach(ctx, d2)) - defer func() { assert.NoError(t, c2.Detach(ctx, d2, false)) }() - assert.NoError(t, c2.Attach(ctx, d3)) - defer func() { assert.NoError(t, c2.Detach(ctx, d3, false)) }() - - watch2Ctx, cancel2 := context.WithCancel(ctx) - _, err = c2.Watch(watch2Ctx, d2) - assert.NoError(t, err) - - watch3Ctx, cancel3 := context.WithCancel(ctx) - _, err = c2.Watch(watch3Ctx, d3) - assert.NoError(t, err) - - // 02. PeersChanged is triggered when another client closes the watch - expected = append(expected, watchResponsePair{ - Type: client.PeersChanged, - Peers: map[string]types.Presence{ - c1.ID().String(): c1.Presence(), - }, - }) - cancel2() - cancel3() - - wgEvents.Wait() - - assert.Equal(t, expected, responsePairs) - }) -} diff --git a/test/integration/presence_test.go b/test/integration/presence_test.go new file mode 100644 index 000000000..1ff65809c --- /dev/null +++ b/test/integration/presence_test.go @@ -0,0 +1,485 @@ +//go:build integration + +/* + * Copyright 2021 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package integration + +import ( + "context" + gojson "encoding/json" + "fmt" + "strconv" + "sync" + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "github.com/yorkie-team/yorkie/client" + "github.com/yorkie-team/yorkie/pkg/document" + "github.com/yorkie-team/yorkie/pkg/document/innerpresence" + "github.com/yorkie-team/yorkie/pkg/document/json" + "github.com/yorkie-team/yorkie/pkg/document/presence" + "github.com/yorkie-team/yorkie/test/helper" +) + +func TestPresence(t *testing.T) { + clients := activeClients(t, 2) + c1, c2 := clients[0], clients[1] + defer deactivateAndCloseClients(t, clients) + + t.Run("update presence by calling Document.Update test", func(t *testing.T) { + // 01. Create a document and attach it to the clients + ctx := context.Background() + d1 := document.New(helper.TestDocKey(t)) + assert.NoError(t, c1.Attach(ctx, d1)) + defer func() { assert.NoError(t, c1.Detach(ctx, d1)) }() + d2 := document.New(helper.TestDocKey(t)) + assert.NoError(t, c2.Attach(ctx, d2)) + defer func() { assert.NoError(t, c2.Detach(ctx, d2)) }() + + // 02. Update the root of the document and presence + assert.NoError(t, d1.Update(func(root *json.Object, p *presence.Presence) error { + root.SetString("key", "value") + p.Set("updated", "true") + return nil + })) + encoded, err := gojson.Marshal(d1.Presences()) + assert.NoError(t, err) + assert.Equal(t, fmt.Sprintf(`{"%s":{"updated":"true"}}`, c1.ID()), string(encoded)) + + // 03 Sync documents and check that the presence is updated on the other client + assert.NoError(t, c1.Sync(ctx)) + assert.NoError(t, c2.Sync(ctx)) + encoded, err = gojson.Marshal(d2.Presences()) + assert.NoError(t, err) + assert.Equal(t, fmt.Sprintf(`{"%s":{"updated":"true"},"%s":{}}`, c1.ID(), c2.ID()), string(encoded)) + }) + + t.Run("presence with snapshot test", func(t *testing.T) { + // 01. Create a document and attach it to the clients + ctx := context.Background() + d1 := document.New(helper.TestDocKey(t)) + assert.NoError(t, c1.Attach(ctx, d1)) + defer func() { assert.NoError(t, c1.Detach(ctx, d1)) }() + d2 := document.New(helper.TestDocKey(t)) + assert.NoError(t, c2.Attach(ctx, d2)) + defer func() { assert.NoError(t, c2.Detach(ctx, d2)) }() + + // 02. Update the root of the document and presence + for i := 0; i < int(helper.SnapshotThreshold); i++ { + assert.NoError(t, d1.Update(func(root *json.Object, p *presence.Presence) error { + root.SetString("key", "value") + p.Set("updated", strconv.Itoa(i)) + return nil + })) + } + encoded, err := gojson.Marshal(d1.Presences()) + assert.NoError(t, err) + assert.Equal(t, fmt.Sprintf(`{"%s":{"updated":"9"}}`, c1.ID()), string(encoded)) + + // 03 Sync documents and check that the presence is updated on the other client + assert.NoError(t, c1.Sync(ctx)) + assert.NoError(t, c2.Sync(ctx)) + encoded, err = gojson.Marshal(d2.Presences()) + assert.NoError(t, err) + assert.Equal(t, fmt.Sprintf(`{"%s":{"updated":"9"},"%s":{}}`, c1.ID(), c2.ID()), string(encoded)) + }) + + t.Run("presence with attach and detach test", func(t *testing.T) { + // 01. Create a document and attach it to the clients + ctx := context.Background() + d1 := document.New(helper.TestDocKey(t)) + assert.NoError(t, c1.Attach(ctx, d1, client.WithPresence(innerpresence.Presence{"key": c1.Key()}))) + d2 := document.New(helper.TestDocKey(t)) + assert.NoError(t, c2.Attach(ctx, d2, client.WithPresence(innerpresence.Presence{"key": c2.Key()}))) + defer func() { assert.NoError(t, c2.Detach(ctx, d2)) }() + + // 02. Check that the presence is updated on the other client. + assert.NoError(t, c1.Sync(ctx)) + assert.Equal(t, innerpresence.Presence{"key": c1.Key()}, d1.MyPresence()) + assert.Equal(t, innerpresence.Presence{"key": c2.Key()}, d1.Presence(c2.ID().String())) + assert.Equal(t, innerpresence.Presence{"key": c2.Key()}, d2.MyPresence()) + assert.Equal(t, innerpresence.Presence{"key": c1.Key()}, d2.Presence(c1.ID().String())) + + // 03. The first client detaches the document and check that the presence is updated on the other client. + assert.NoError(t, c1.Detach(ctx, d1)) + assert.NoError(t, c2.Sync(ctx)) + assert.Equal(t, innerpresence.Presence{"key": c2.Key()}, d2.MyPresence()) + assert.Nil(t, d2.Presence(c1.ID().String())) + }) + + t.Run("presence-related events test", func(t *testing.T) { + // 01. Create two clients and documents and attach them. + ctx := context.Background() + d1 := document.New(helper.TestDocKey(t)) + d2 := document.New(helper.TestDocKey(t)) + assert.NoError(t, c1.Attach(ctx, d1)) + defer func() { assert.NoError(t, c1.Detach(ctx, d1)) }() + assert.NoError(t, c2.Attach(ctx, d2)) + defer func() { assert.NoError(t, c2.Detach(ctx, d2)) }() + + // 02. Watch the first client's document. + var expected []watchResponsePair + var responsePairs []watchResponsePair + wgEvents := sync.WaitGroup{} + wgEvents.Add(1) + + watch1Ctx, cancel1 := context.WithCancel(ctx) + defer cancel1() + wrch, err := c1.Watch(watch1Ctx, d1) + assert.NoError(t, err) + go func() { + defer func() { + wgEvents.Done() + }() + for { + select { + case <-time.After(time.Second): + assert.Fail(t, "timeout") + return + case wr := <-wrch: + if wr.Err != nil { + assert.Fail(t, "unexpected stream closing", wr.Err) + return + } + if wr.Type != client.DocumentChanged { + responsePairs = append(responsePairs, watchResponsePair{ + Type: wr.Type, + Presences: wr.Presences, + }) + } + if len(responsePairs) == 3 { + return + } + } + } + }() + + // 03. Watch the second client's document. + expected = append(expected, watchResponsePair{ + Type: client.DocumentWatched, + Presences: map[string]innerpresence.Presence{ + c2.ID().String(): {}, + }, + }) + watch2Ctx, cancel2 := context.WithCancel(ctx) + _, err = c2.Watch(watch2Ctx, d2) + assert.NoError(t, err) + + // 04. Update the second client's presence. + err = d2.Update(func(root *json.Object, p *presence.Presence) error { + p.Set("updated", "true") + return nil + }) + assert.NoError(t, err) + expected = append(expected, watchResponsePair{ + Type: client.PresenceChanged, + Presences: map[string]innerpresence.Presence{ + c2.ID().String(): d2.MyPresence(), + }, + }) + assert.NoError(t, c2.Sync(ctx, client.WithDocKey(helper.TestDocKey(t)))) + assert.NoError(t, c1.Sync(ctx, client.WithDocKey(helper.TestDocKey(t)))) + + // 05. Unwatch the second client's document. + expected = append(expected, watchResponsePair{ + Type: client.DocumentUnwatched, + Presences: map[string]innerpresence.Presence{ + c2.ID().String(): d2.MyPresence(), + }, + }) + cancel2() + + wgEvents.Wait() + assert.Equal(t, expected, responsePairs) + }) + + t.Run("unwatch after detach events test", func(t *testing.T) { + // 01. Create two clients and documents and attach them. + ctx := context.Background() + d1 := document.New(helper.TestDocKey(t)) + d2 := document.New(helper.TestDocKey(t)) + assert.NoError(t, c1.Attach(ctx, d1)) + defer func() { assert.NoError(t, c1.Detach(ctx, d1)) }() + assert.NoError(t, c2.Attach(ctx, d2)) + + // 02. Watch the first client's document. + var expected []watchResponsePair + var responsePairs []watchResponsePair + wgEvents := sync.WaitGroup{} + wgEvents.Add(1) + + watch1Ctx, cancel1 := context.WithCancel(ctx) + defer cancel1() + wrch, err := c1.Watch(watch1Ctx, d1) + assert.NoError(t, err) + go func() { + defer func() { + wgEvents.Done() + }() + for { + select { + case <-time.After(10 * time.Second): + assert.Fail(t, "timeout") + return + case wr := <-wrch: + if wr.Err != nil { + assert.Fail(t, "unexpected stream closing", wr.Err) + return + } + if wr.Type != client.DocumentChanged { + responsePairs = append(responsePairs, watchResponsePair{ + Type: wr.Type, + Presences: wr.Presences, + }) + } + + if len(responsePairs) == 4 { + return + } + } + } + }() + + // 03. Watch the second client's document. + expected = append(expected, watchResponsePair{ + Type: client.DocumentWatched, + Presences: map[string]innerpresence.Presence{ + c2.ID().String(): {}, + }, + }) + watch2Ctx, cancel2 := context.WithCancel(ctx) + defer cancel2() + _, err = c2.Watch(watch2Ctx, d2) + assert.NoError(t, err) + + // 04. Update the second client's presence. + err = d2.Update(func(root *json.Object, p *presence.Presence) error { + p.Set("updated", "true") + return nil + }) + assert.NoError(t, err) + expected = append(expected, watchResponsePair{ + Type: client.PresenceChanged, + Presences: map[string]innerpresence.Presence{ + c2.ID().String(): d2.MyPresence(), + }, + }) + assert.NoError(t, c2.Sync(ctx, client.WithDocKey(helper.TestDocKey(t)))) + assert.NoError(t, c1.Sync(ctx, client.WithDocKey(helper.TestDocKey(t)))) + + // 05. Unwatch the second client's document. + expected = append(expected, watchResponsePair{ + Type: client.PresenceChanged, + Presences: map[string]innerpresence.Presence{ + c2.ID().String(): nil, + }, + }) + assert.NoError(t, c2.Detach(ctx, d2)) + assert.NoError(t, c1.Sync(ctx, client.WithDocKey(helper.TestDocKey(t)))) + + expected = append(expected, watchResponsePair{ + Type: client.DocumentUnwatched, + Presences: map[string]innerpresence.Presence{ + c2.ID().String(): nil, + }, + }) + cancel2() + + wgEvents.Wait() + assert.Equal(t, expected, responsePairs) + }) + + t.Run("detach after unwatch events test", func(t *testing.T) { + // 01. Create two clients and documents and attach them. + ctx := context.Background() + d1 := document.New(helper.TestDocKey(t)) + d2 := document.New(helper.TestDocKey(t)) + assert.NoError(t, c1.Attach(ctx, d1)) + defer func() { assert.NoError(t, c1.Detach(ctx, d1)) }() + assert.NoError(t, c2.Attach(ctx, d2)) + + // 02. Watch the first client's document. + var expected []watchResponsePair + var responsePairs []watchResponsePair + wgEvents := sync.WaitGroup{} + wgEvents.Add(1) + + watch1Ctx, cancel1 := context.WithCancel(ctx) + defer cancel1() + wrch, err := c1.Watch(watch1Ctx, d1) + assert.NoError(t, err) + go func() { + defer func() { + wgEvents.Done() + }() + for { + select { + case <-time.After(10 * time.Second): + assert.Fail(t, "timeout") + return + case wr := <-wrch: + if wr.Err != nil { + assert.Fail(t, "unexpected stream closing", wr.Err) + return + } + if wr.Type != client.DocumentChanged { + responsePairs = append(responsePairs, watchResponsePair{ + Type: wr.Type, + Presences: wr.Presences, + }) + } + + if len(responsePairs) == 3 { + return + } + } + } + }() + + // 03. Watch the second client's document. + expected = append(expected, watchResponsePair{ + Type: client.DocumentWatched, + Presences: map[string]innerpresence.Presence{ + c2.ID().String(): {}, + }, + }) + watch2Ctx, cancel2 := context.WithCancel(ctx) + defer cancel2() + _, err = c2.Watch(watch2Ctx, d2) + assert.NoError(t, err) + + // 04. Update the second client's presence. + err = d2.Update(func(root *json.Object, p *presence.Presence) error { + p.Set("updated", "true") + return nil + }) + assert.NoError(t, err) + expected = append(expected, watchResponsePair{ + Type: client.PresenceChanged, + Presences: map[string]innerpresence.Presence{ + c2.ID().String(): d2.MyPresence(), + }, + }) + assert.NoError(t, c2.Sync(ctx, client.WithDocKey(helper.TestDocKey(t)))) + assert.NoError(t, c1.Sync(ctx, client.WithDocKey(helper.TestDocKey(t)))) + + // 05. Unwatch the second client's document. + expected = append(expected, watchResponsePair{ + Type: client.DocumentUnwatched, + Presences: map[string]innerpresence.Presence{ + c2.ID().String(): d2.MyPresence(), + }, + }) + cancel2() + + assert.NoError(t, c2.Detach(ctx, d2)) + assert.NoError(t, c1.Sync(ctx, client.WithDocKey(helper.TestDocKey(t)))) + + wgEvents.Wait() + assert.Equal(t, expected, responsePairs) + }) + + t.Run("watching multiple documents test", func(t *testing.T) { + ctx := context.Background() + + // 01. Two clients attach two documents with the same key, and watch them. + // But the second client also attaches another document. + d1 := document.New(helper.TestDocKey(t)) + d2 := document.New(helper.TestDocKey(t)) + d3 := document.New(helper.TestDocKey(t) + "2") + assert.NoError(t, c1.Attach(ctx, d1)) + defer func() { assert.NoError(t, c1.Detach(ctx, d1)) }() + + // 02. Watch the first client's document. + var expected []watchResponsePair + var responsePairs []watchResponsePair + wgEvents := sync.WaitGroup{} + wgEvents.Add(1) + + watch1Ctx, cancel1 := context.WithCancel(ctx) + defer cancel1() + wrch, err := c1.Watch(watch1Ctx, d1) + assert.NoError(t, err) + go func() { + defer func() { + wgEvents.Done() + }() + for { + select { + case <-time.After(time.Second): + assert.Fail(t, "timeout") + return + case wr := <-wrch: + if wr.Err != nil { + assert.Fail(t, "unexpected stream closing", wr.Err) + return + } + + if wr.Type != client.DocumentChanged { + responsePairs = append(responsePairs, watchResponsePair{ + Type: wr.Type, + Presences: wr.Presences, + }) + } + + if len(responsePairs) == 2 { + return + } + } + } + }() + + // 03. The second client attaches a document with the same key as the first client's document + // and another document with a different key. + assert.NoError(t, c2.Attach(ctx, d2)) + defer func() { assert.NoError(t, c2.Detach(ctx, d2)) }() + assert.NoError(t, c2.Attach(ctx, d3)) + defer func() { assert.NoError(t, c2.Detach(ctx, d3)) }() + + // 04. The second client watches the documents attached by itself. + expected = append(expected, watchResponsePair{ + Type: client.DocumentWatched, + Presences: map[string]innerpresence.Presence{ + c2.ID().String(): d2.MyPresence(), + }, + }) + watch2Ctx, cancel2 := context.WithCancel(ctx) + _, err = c2.Watch(watch2Ctx, d2) + assert.NoError(t, err) + assert.NoError(t, c1.Sync(ctx, client.WithDocKey(helper.TestDocKey(t)))) + + watch3Ctx, cancel3 := context.WithCancel(ctx) + _, err = c2.Watch(watch3Ctx, d3) + assert.NoError(t, err) + + // 05. The second client unwatch the documents attached by itself. + expected = append(expected, watchResponsePair{ + Type: client.DocumentUnwatched, + Presences: map[string]innerpresence.Presence{ + c2.ID().String(): {}, + }, + }) + cancel2() + cancel3() + + wgEvents.Wait() + + assert.Equal(t, expected, responsePairs) + }) +} diff --git a/test/integration/primitive_test.go b/test/integration/primitive_test.go index 24f2e8303..747eb598a 100644 --- a/test/integration/primitive_test.go +++ b/test/integration/primitive_test.go @@ -27,6 +27,7 @@ import ( "github.com/yorkie-team/yorkie/pkg/document" "github.com/yorkie-team/yorkie/pkg/document/json" + "github.com/yorkie-team/yorkie/pkg/document/presence" "github.com/yorkie-team/yorkie/test/helper" ) @@ -41,7 +42,7 @@ func TestPrimitive(t *testing.T) { err := c1.Attach(ctx, d1) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewObject("k1"). SetBool("k1.1", true). SetInteger("k1.2", 2147483647). diff --git a/test/integration/retention_test.go b/test/integration/retention_test.go index 2f33cd3fa..fc36fa2df 100644 --- a/test/integration/retention_test.go +++ b/test/integration/retention_test.go @@ -20,7 +20,6 @@ package integration import ( "context" - "fmt" "log" "reflect" "testing" @@ -28,11 +27,11 @@ import ( "github.com/stretchr/testify/assert" monkey "github.com/undefinedlabs/go-mpatch" - "github.com/yorkie-team/yorkie/api/types" "github.com/yorkie-team/yorkie/client" "github.com/yorkie-team/yorkie/pkg/document" "github.com/yorkie-team/yorkie/pkg/document/change" "github.com/yorkie-team/yorkie/pkg/document/json" + "github.com/yorkie-team/yorkie/pkg/document/presence" "github.com/yorkie-team/yorkie/server" "github.com/yorkie-team/yorkie/server/backend/background" "github.com/yorkie-team/yorkie/server/backend/database/mongo" @@ -57,6 +56,7 @@ func TestRetention(t *testing.T) { t.Run("history test with purging changes", func(t *testing.T) { conf := helper.TestConfig() conf.Backend.SnapshotWithPurgingChanges = true + conf.Backend.SnapshotInterval = 0 testServer, err := server.New(conf) if err != nil { log.Fatal(err) @@ -66,10 +66,7 @@ func TestRetention(t *testing.T) { logging.DefaultLogger().Fatal(err) } - cli, err := client.Dial( - testServer.RPCAddr(), - client.WithPresence(types.Presence{"name": fmt.Sprintf("name-%d", 0)}), - ) + cli, err := client.Dial(testServer.RPCAddr()) assert.NoError(t, err) assert.NoError(t, cli.Activate(context.Background())) defer func() { @@ -85,21 +82,21 @@ func TestRetention(t *testing.T) { doc := document.New(helper.TestDocKey(t)) assert.NoError(t, cli.Attach(ctx, doc)) - defer func() { assert.NoError(t, cli.Detach(ctx, doc, false)) }() + defer func() { assert.NoError(t, cli.Detach(ctx, doc)) }() - assert.NoError(t, doc.Update(func(root *json.Object) error { + assert.NoError(t, doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewArray("todos") return nil }, "create todos")) assert.Equal(t, `{"todos":[]}`, doc.Marshal()) - assert.NoError(t, doc.Update(func(root *json.Object) error { + assert.NoError(t, doc.Update(func(root *json.Object, p *presence.Presence) error { root.GetArray("todos").AddString("buy coffee") return nil }, "buy coffee")) assert.Equal(t, `{"todos":["buy coffee"]}`, doc.Marshal()) - assert.NoError(t, doc.Update(func(root *json.Object) error { + assert.NoError(t, doc.Update(func(root *json.Object, p *presence.Presence) error { root.GetArray("todos").AddString("buy bread") return nil }, "buy bread")) @@ -120,6 +117,7 @@ func TestRetention(t *testing.T) { t.Run("snapshot with purging changes test", func(t *testing.T) { serverConfig := helper.TestConfig() // Default SnapshotInterval is 0, SnapshotThreshold must also be 0 + serverConfig.Backend.SnapshotInterval = 0 serverConfig.Backend.SnapshotThreshold = 0 serverConfig.Backend.SnapshotWithPurgingChanges = true testServer, err := server.New(serverConfig) @@ -131,10 +129,7 @@ func TestRetention(t *testing.T) { logging.DefaultLogger().Fatal(err) } - cli1, err := client.Dial( - testServer.RPCAddr(), - client.WithPresence(types.Presence{"name": fmt.Sprintf("name-%d", 0)}), - ) + cli1, err := client.Dial(testServer.RPCAddr()) assert.NoError(t, err) err = cli1.Activate(context.Background()) @@ -147,9 +142,9 @@ func TestRetention(t *testing.T) { ctx := context.Background() d1 := document.New(helper.TestDocKey(t)) assert.NoError(t, cli1.Attach(ctx, d1)) - defer func() { assert.NoError(t, cli1.Detach(ctx, d1, false)) }() + defer func() { assert.NoError(t, cli1.Detach(ctx, d1)) }() - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewText("k1") return nil }) @@ -167,7 +162,7 @@ func TestRetention(t *testing.T) { // Create 6 changes for _, edit := range edits { - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.GetText("k1").Edit(edit.from, edit.to, edit.content) return nil }) @@ -207,10 +202,7 @@ func TestRetention(t *testing.T) { // one is most recent ServerSeq and one is one older from the most recent ServerSeq assert.Len(t, changes, 2) - cli2, err := client.Dial( - testServer.RPCAddr(), - client.WithPresence(types.Presence{"name": fmt.Sprintf("name-%d", 1)}), - ) + cli2, err := client.Dial(testServer.RPCAddr()) assert.NoError(t, err) err = cli2.Activate(context.Background()) @@ -222,11 +214,11 @@ func TestRetention(t *testing.T) { d2 := document.New(helper.TestDocKey(t)) assert.NoError(t, cli2.Attach(ctx, d2)) - defer func() { assert.NoError(t, cli2.Detach(ctx, d2, false)) }() + defer func() { assert.NoError(t, cli2.Detach(ctx, d2)) }() // Create 6 changes for _, edit := range edits { - err = d2.Update(func(root *json.Object) error { + err = d2.Update(func(root *json.Object, p *presence.Presence) error { root.GetText("k1").Edit(edit.from, edit.to, edit.content) return nil }) @@ -243,6 +235,6 @@ func TestRetention(t *testing.T) { ) assert.NoError(t, err) - assert.Len(t, changes, 8) + assert.Len(t, changes, 9) }) } diff --git a/test/integration/snapshot_test.go b/test/integration/snapshot_test.go index a4f03ca2b..7e3cc3a73 100644 --- a/test/integration/snapshot_test.go +++ b/test/integration/snapshot_test.go @@ -30,6 +30,7 @@ import ( "github.com/yorkie-team/yorkie/pkg/document" "github.com/yorkie-team/yorkie/pkg/document/json" + "github.com/yorkie-team/yorkie/pkg/document/presence" "github.com/yorkie-team/yorkie/server/backend/background" "github.com/yorkie-team/yorkie/test/helper" ) @@ -65,7 +66,7 @@ func TestSnapshot(t *testing.T) { // 01. Update changes over snapshot threshold. for i := 0; i <= int(helper.SnapshotThreshold); i++ { - err := d1.Update(func(root *json.Object) error { + err := d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetInteger(fmt.Sprintf("%d", i), i) return nil }) @@ -75,7 +76,7 @@ func TestSnapshot(t *testing.T) { assert.NoError(t, err) // 02. Makes local changes then pull a snapshot from the server. - err = d2.Update(func(root *json.Object) error { + err = d2.Update(func(root *json.Object, p *presence.Presence) error { root.SetString("key", "value") return nil }) @@ -95,7 +96,7 @@ func TestSnapshot(t *testing.T) { err := c1.Attach(ctx, d1) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewText("k1") return nil }) @@ -116,7 +117,7 @@ func TestSnapshot(t *testing.T) { } for _, edit := range edits { - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.GetText("k1").Edit(edit.from, edit.to, edit.content) return nil }) @@ -140,7 +141,7 @@ func TestSnapshot(t *testing.T) { err := c1.Attach(ctx, d1) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewText("k1") return nil }) @@ -153,14 +154,14 @@ func TestSnapshot(t *testing.T) { assert.NoError(t, err) for i := 0; i <= int(helper.SnapshotThreshold); i++ { - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.GetText("k1").Edit(i, i, "x") return nil }) assert.NoError(t, err) } - err = d2.Update(func(root *json.Object) error { + err = d2.Update(func(root *json.Object, p *presence.Presence) error { root.GetText("k1").Edit(0, 0, "o") return nil }) diff --git a/test/integration/text_test.go b/test/integration/text_test.go index c7e39dc0a..3d1e0287f 100644 --- a/test/integration/text_test.go +++ b/test/integration/text_test.go @@ -26,6 +26,7 @@ import ( "github.com/yorkie-team/yorkie/pkg/document" "github.com/yorkie-team/yorkie/pkg/document/json" + "github.com/yorkie-team/yorkie/pkg/document/presence" "github.com/yorkie-team/yorkie/test/helper" ) @@ -40,7 +41,7 @@ func TestText(t *testing.T) { err := c1.Attach(ctx, d1) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewText("k1") return nil }, "set a new text by c1") @@ -52,13 +53,13 @@ func TestText(t *testing.T) { err = c2.Attach(ctx, d2) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.GetText("k1").Edit(0, 0, "ABCD") return nil }, "edit 0,0 ABCD by c1") assert.NoError(t, err) - err = d2.Update(func(root *json.Object) error { + err = d2.Update(func(root *json.Object, p *presence.Presence) error { root.GetText("k1").Edit(0, 0, "1234") return nil }, "edit 0,0 1234 by c2") @@ -66,13 +67,13 @@ func TestText(t *testing.T) { syncClientsThenAssertEqual(t, []clientAndDocPair{{c1, d1}, {c2, d2}}) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.GetText("k1").Edit(2, 3, "XX") return nil }, "edit 2,3 XX by c1") assert.NoError(t, err) - err = d2.Update(func(root *json.Object) error { + err = d2.Update(func(root *json.Object, p *presence.Presence) error { root.GetText("k1").Edit(2, 3, "YY") return nil }, "edit 2,3 YY by c2") @@ -80,13 +81,13 @@ func TestText(t *testing.T) { syncClientsThenAssertEqual(t, []clientAndDocPair{{c1, d1}, {c2, d2}}) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.GetText("k1").Edit(4, 5, "ZZ") return nil }, "edit 4,5 ZZ by c1") assert.NoError(t, err) - err = d2.Update(func(root *json.Object) error { + err = d2.Update(func(root *json.Object, p *presence.Presence) error { root.GetText("k1").Edit(2, 3, "TT") return nil }, "edit 2,3 TT by c2") @@ -101,7 +102,7 @@ func TestText(t *testing.T) { err := c1.Attach(ctx, d1) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewText("k1").Edit(0, 0, "Hello world", nil) return nil }, `set a new text with "Hello world" by c1`) @@ -113,14 +114,14 @@ func TestText(t *testing.T) { err = c2.Attach(ctx, d2) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { text := root.GetText("k1") text.Style(0, 1, map[string]string{"b": "1"}) return nil }, `set style b to "H" by c1`) assert.NoError(t, err) - err = d2.Update(func(root *json.Object) error { + err = d2.Update(func(root *json.Object, p *presence.Presence) error { text := root.GetText("k1") text.Style(0, 5, map[string]string{"i": "1"}) return nil @@ -136,7 +137,7 @@ func TestText(t *testing.T) { err := c1.Attach(ctx, d1) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewText("k1") return nil }, "set a new text by c1") @@ -148,7 +149,7 @@ func TestText(t *testing.T) { err = c2.Attach(ctx, d2) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.GetText("k1").Edit(0, 0, "123") root.GetText("k1").Edit(3, 3, "456") root.GetText("k1").Edit(6, 6, "789") @@ -159,14 +160,14 @@ func TestText(t *testing.T) { syncClientsThenAssertEqual(t, []clientAndDocPair{{c1, d1}, {c2, d2}}) assert.Equal(t, `{"k1":[{"val":"123"},{"val":"456"},{"val":"789"}]}`, d2.Marshal()) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.GetText("k1").Edit(1, 7, "") return nil }, "delete block by c1") assert.NoError(t, err) assert.Equal(t, `{"k1":[{"val":"1"},{"val":"89"}]}`, d1.Marshal()) - err = d2.Update(func(root *json.Object) error { + err = d2.Update(func(root *json.Object, p *presence.Presence) error { root.GetText("k1").Edit(2, 5, "") return nil }, "delete block by c2") @@ -182,7 +183,7 @@ func TestText(t *testing.T) { err := c1.Attach(ctx, d1) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewText("k1") return nil }, "set a new text by c1") @@ -194,7 +195,7 @@ func TestText(t *testing.T) { err = c2.Attach(ctx, d2) assert.NoError(t, err) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.GetText("k1").Edit(0, 0, "0") root.GetText("k1").Edit(1, 1, "0") root.GetText("k1").Edit(2, 2, "0") @@ -205,7 +206,7 @@ func TestText(t *testing.T) { syncClientsThenAssertEqual(t, []clientAndDocPair{{c1, d1}, {c2, d2}}) assert.Equal(t, `{"k1":[{"val":"0"},{"val":"0"},{"val":"0"}]}`, d2.Marshal()) - err = d1.Update(func(root *json.Object) error { + err = d1.Update(func(root *json.Object, p *presence.Presence) error { root.GetText("k1").Edit(1, 2, "1") root.GetText("k1").Edit(1, 2, "1") root.GetText("k1").Edit(1, 2, "") @@ -214,7 +215,7 @@ func TestText(t *testing.T) { assert.NoError(t, err) assert.Equal(t, `{"k1":[{"val":"0"},{"val":"0"}]}`, d1.Marshal()) - err = d2.Update(func(root *json.Object) error { + err = d2.Update(func(root *json.Object, p *presence.Presence) error { root.GetText("k1").Edit(0, 3, "") return nil }, "delete the range includes above new nodes") diff --git a/test/integration/tree_test.go b/test/integration/tree_test.go index beceb8f44..2d6d36edb 100644 --- a/test/integration/tree_test.go +++ b/test/integration/tree_test.go @@ -26,6 +26,7 @@ import ( "github.com/yorkie-team/yorkie/pkg/document" "github.com/yorkie-team/yorkie/pkg/document/json" + "github.com/yorkie-team/yorkie/pkg/document/presence" "github.com/yorkie-team/yorkie/test/helper" ) @@ -36,7 +37,7 @@ func TestTree(t *testing.T) { t.Run("tree", func(t *testing.T) { doc := document.New(helper.TestDocKey(t)) - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { // 01. Create a tree and insert a paragraph. root.SetNewTree("t").Edit(0, 0, &json.TreeNode{ Type: "p", @@ -92,7 +93,7 @@ func TestTree(t *testing.T) { t.Run("created from JSON test", func(t *testing.T) { doc := document.New(helper.TestDocKey(t)) - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewTree("t", &json.TreeNode{ Type: "doc", Children: []json.TreeNode{{ @@ -119,7 +120,7 @@ func TestTree(t *testing.T) { t.Run("created from JSON with attributes test", func(t *testing.T) { doc := document.New(helper.TestDocKey(t)) - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewTree("t", &json.TreeNode{ Type: "doc", Children: []json.TreeNode{{ @@ -139,7 +140,7 @@ func TestTree(t *testing.T) { t.Run("edit its content test", func(t *testing.T) { doc := document.New(helper.TestDocKey(t)) - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewTree("t", &json.TreeNode{ Type: "doc", Children: []json.TreeNode{{ @@ -172,7 +173,7 @@ func TestTree(t *testing.T) { assert.NoError(t, err) assert.Equal(t, "

ab

", doc.Root().GetTree("t").ToXML()) - err = doc.Update(func(root *json.Object) error { + err = doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewTree("t", &json.TreeNode{ Type: "doc", Children: []json.TreeNode{{ @@ -201,7 +202,7 @@ func TestTree(t *testing.T) { t.Run("edit its content with path", func(t *testing.T) { doc := document.New(helper.TestDocKey(t)) - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewTree("t", &json.TreeNode{ Type: "doc", Children: []json.TreeNode{{ @@ -241,7 +242,7 @@ func TestTree(t *testing.T) { t.Run("edit its content when multi tree nodes passed", func(t *testing.T) { doc := document.New(helper.TestDocKey(t)) - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewTree("t", &json.TreeNode{ Type: "doc", Children: []json.TreeNode{{ @@ -287,7 +288,7 @@ func TestTree(t *testing.T) { t.Run("edit its content with attributes test", func(t *testing.T) { doc := document.New(helper.TestDocKey(t)) - err := doc.Update(func(root *json.Object) error { + err := doc.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewTree("t", &json.TreeNode{Type: "doc"}) assert.Equal(t, "", root.GetTree("t").ToXML()) @@ -319,7 +320,7 @@ func TestTree(t *testing.T) { d1 := document.New(helper.TestDocKey(t)) assert.NoError(t, c1.Attach(ctx, d1)) - assert.NoError(t, d1.Update(func(root *json.Object) error { + assert.NoError(t, d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewTree("t", &json.TreeNode{ Type: "root", Children: []json.TreeNode{{ @@ -344,7 +345,7 @@ func TestTree(t *testing.T) { d1 := document.New(helper.TestDocKey(t)) assert.NoError(t, c1.Attach(ctx, d1)) - assert.NoError(t, d1.Update(func(root *json.Object) error { + assert.NoError(t, d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewTree("t", &json.TreeNode{ Type: "root", Children: []json.TreeNode{ @@ -357,7 +358,7 @@ func TestTree(t *testing.T) { assert.NoError(t, c1.Sync(ctx)) assert.Equal(t, `

ab

cd

`, d1.Root().GetTree("t").ToXML()) - assert.NoError(t, d1.Update(func(root *json.Object) error { + assert.NoError(t, d1.Update(func(root *json.Object, p *presence.Presence) error { root.GetTree("t").Style(3, 4, map[string]string{"bold": "true"}) return nil })) @@ -378,7 +379,7 @@ func TestTree(t *testing.T) { d1 := document.New(helper.TestDocKey(t)) assert.NoError(t, c1.Attach(ctx, d1)) - assert.NoError(t, d1.Update(func(root *json.Object) error { + assert.NoError(t, d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewTree("t", &json.TreeNode{ Type: "root", Children: []json.TreeNode{{ @@ -394,11 +395,11 @@ func TestTree(t *testing.T) { d2 := document.New(helper.TestDocKey(t)) assert.NoError(t, c2.Attach(ctx, d2)) - assert.NoError(t, d1.Update(func(root *json.Object) error { + assert.NoError(t, d1.Update(func(root *json.Object, p *presence.Presence) error { root.GetTree("t").Edit(1, 1, &json.TreeNode{Type: "text", Value: "A"}) return nil })) - assert.NoError(t, d2.Update(func(root *json.Object) error { + assert.NoError(t, d2.Update(func(root *json.Object, p *presence.Presence) error { root.GetTree("t").Edit(1, 1, &json.TreeNode{Type: "text", Value: "B"}) return nil })) @@ -414,7 +415,7 @@ func TestTree(t *testing.T) { d1 := document.New(helper.TestDocKey(t)) assert.NoError(t, c1.Attach(ctx, d1)) - assert.NoError(t, d1.Update(func(root *json.Object) error { + assert.NoError(t, d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewTree("t", &json.TreeNode{ Type: "root", Children: []json.TreeNode{{ @@ -430,11 +431,11 @@ func TestTree(t *testing.T) { d2 := document.New(helper.TestDocKey(t)) assert.NoError(t, c2.Attach(ctx, d2)) - assert.NoError(t, d1.Update(func(root *json.Object) error { + assert.NoError(t, d1.Update(func(root *json.Object, p *presence.Presence) error { root.GetTree("t").Edit(2, 2, &json.TreeNode{Type: "text", Value: "A"}) return nil })) - assert.NoError(t, d2.Update(func(root *json.Object) error { + assert.NoError(t, d2.Update(func(root *json.Object, p *presence.Presence) error { root.GetTree("t").Edit(2, 2, &json.TreeNode{Type: "text", Value: "B"}) return nil })) @@ -449,7 +450,7 @@ func TestTree(t *testing.T) { d1 := document.New(helper.TestDocKey(t)) assert.NoError(t, c1.Attach(ctx, d1)) - assert.NoError(t, d1.Update(func(root *json.Object) error { + assert.NoError(t, d1.Update(func(root *json.Object, p *presence.Presence) error { root.SetNewTree("t", &json.TreeNode{ Type: "root", Children: []json.TreeNode{{ @@ -465,11 +466,11 @@ func TestTree(t *testing.T) { d2 := document.New(helper.TestDocKey(t)) assert.NoError(t, c2.Attach(ctx, d2)) - assert.NoError(t, d1.Update(func(root *json.Object) error { + assert.NoError(t, d1.Update(func(root *json.Object, p *presence.Presence) error { root.GetTree("t").Edit(3, 3, &json.TreeNode{Type: "text", Value: "A"}) return nil })) - assert.NoError(t, d2.Update(func(root *json.Object) error { + assert.NoError(t, d2.Update(func(root *json.Object, p *presence.Presence) error { root.GetTree("t").Edit(3, 3, &json.TreeNode{Type: "text", Value: "B"}) return nil }))