diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e3254891d..e438e5b88 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,6 +8,7 @@ on: paths-ignore: - 'api/docs/**' - 'build/charts/**' + - 'design/**' - '**/*.md' - '**/*.txt' - '**/.gitignore' @@ -16,11 +17,44 @@ env: GO_VERSION: '1.21' jobs: + ci-target-check: + runs-on: ubuntu-latest + + outputs: + build: ${{ steps.ci-target-check.outputs.build }} + bench: ${{ steps.ci-target-check.outputs.bench }} + complex-test: ${{ steps.ci-target-check.outputs.complex-test }} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: CI target check by path + uses: dorny/paths-filter@v3 + id: ci-target-check + with: + filters: | + build: '**' + bench: + - 'pkg/**' + - 'server/**' + - 'client/**' + - 'admin/**' + - 'api/converter/**' + + complex-test: + - 'server/backend/database/**' + - 'pkg/document/**' + - 'client/**' + build: name: build runs-on: ubuntu-latest - steps: + needs: ci-target-check + if: ${{ needs.ci-target-check.outputs.build == 'true' }} + + steps: - name: Set up Go ${{ env.GO_VERSION }} uses: actions/setup-go@v4 with: @@ -47,7 +81,7 @@ jobs: run: make build - name: Stack - run: docker-compose -f build/docker/docker-compose.yml up --build -d + run: docker compose -f build/docker/docker-compose.yml up --build -d - name: Test run: go test -tags integration -race -coverprofile=coverage.txt -covermode=atomic -v ./... @@ -58,11 +92,15 @@ jobs: file: ./coverage.txt env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - + bench: name: bench runs-on: ubuntu-latest permissions: write-all + + needs: ci-target-check + if: ${{ needs.ci-target-check.outputs.bench == 'true' }} + steps: - name: Set up Go ${{ env.GO_VERSION }} @@ -73,11 +111,8 @@ jobs: - name: Check out code uses: actions/checkout@v4 - - name: Get tools dependencies - run: make tools - - name: Stack - run: docker-compose -f build/docker/docker-compose.yml up --build -d + run: docker compose -f build/docker/docker-compose.yml up --build -d - name: Bench run: make bench @@ -100,9 +135,13 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} comment-always: true - sharding_test: - name: sharding_test + complex-test: + name: complex-test runs-on: ubuntu-latest + + needs: ci-target-check + if: ${{ needs.ci-target-check.outputs.complex-test == 'true' }} + steps: - name: Set up Go ${{ env.GO_VERSION }} @@ -113,9 +152,6 @@ jobs: - name: Check out code uses: actions/checkout@v4 - - name: Get tools dependencies - run: make tools - - name: Check Docker Compose Version run: docker compose --version @@ -127,7 +163,7 @@ jobs: - name: Initialize the Shard 1 run: docker compose -f build/docker/sharding/docker-compose.yml exec shard1-1 mongosh test /scripts/init-shard1-1.js - + - name: Initialize the Shard 2 run: docker compose -f build/docker/sharding/docker-compose.yml exec shard2-1 mongosh test /scripts/init-shard2-1.js @@ -137,5 +173,5 @@ jobs: - name: Initialize the Mongos run: docker compose -f build/docker/sharding/docker-compose.yml exec mongos1 mongosh test /scripts/init-mongos1.js - - name: Run the tests with sharding tag - run: go test -tags sharding -race -v ./test/sharding/... + - name: Run the tests with complex tag + run: go test -tags complex -race -v ./test/complex/... diff --git a/CHANGELOG.md b/CHANGELOG.md index 824d830b5..492551aba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,72 @@ and Yorkie adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) ## [Unreleased] +## [0.5.0] - 2024-09-05 + +### Added + +- Add Concurrency Tests between Array Operations by @cloneot in https://github.com/yorkie-team/yorkie/pull/985 +- Add metric for WatchDocument streams by @emplam27 in https://github.com/yorkie-team/yorkie/pull/998 +- Add Account Deletion and Change Password to CLI by @sigmaith in https://github.com/yorkie-team/yorkie/pull/983 + +### Changed + +- Optimize FindChangeInfosBetweenServerSeqs to prevent unnecessary Query by @kokodak in https://github.com/yorkie-team/yorkie/pull/974 +- Rename SetByIndex to ArraySet by @hackerwins in https://github.com/yorkie-team/yorkie/pull/995 + +### Fixed + +- Set `updated_at` with `created_at` when creating Document by @window9u in https://github.com/yorkie-team/yorkie/pull/977 + +## [0.4.31] - 2024-08-21 + +### Added + +- Add a metric to collect the number of background routines by @kokodak in https://github.com/yorkie-team/yorkie/pull/963 + +### Changed + +- Modify health check endpoint and add HEAD method by @taeng0204 in https://github.com/yorkie-team/yorkie/pull/958 +- [Revised] Fine-tuned CI Workflows in PR by @krapie in https://github.com/yorkie-team/yorkie/pull/965 + +### Fixed + +- Fix invalid test case in FindDocInfosByKeys by @kokodak in https://github.com/yorkie-team/yorkie/pull/972 + +## [0.4.30] - 2024-08-09 + +### Added + +- Add HTTP health check handler for server health monitoring by @taeng0204 in https://github.com/yorkie-team/yorkie/pull/952 +- Show Server Version in Yorkie CLI by @hyun98 in https://github.com/yorkie-team/yorkie/pull/938 + +## [0.4.29] - 2024-08-05 + +### Added + +- Support basic account action for admin by @gusah009 in https://github.com/yorkie-team/yorkie/pull/934 + +### Changed + +- Update docker compose command to V2 by @fourjae in https://github.com/yorkie-team/yorkie/pull/950 + +### Fixed + +- Fix FindDocInfosByKeys when keys is empty by @blurfx in https://github.com/yorkie-team/yorkie/pull/945 +- Handle panic during conversion to connectCode by @blurfx in https://github.com/yorkie-team/yorkie/pull/951 + +## [0.4.28] - 2024-07-25 + +### Added + +- Enhance housekeeping to add variety of tasks by @hackerwins in https://github.com/yorkie-team/yorkie/pull/932 +- Enhance GetDocuments API by adding bulk retrieval by @kokodak in https://github.com/yorkie-team/yorkie/pull/931 +- Improve performance for creating crdt.TreeNode by @m4ushold in https://github.com/yorkie-team/yorkie/pull/939 + +### Changed + +- Update `updated_at` only when there are operations in changes by @window9u in https://github.com/yorkie-team/yorkie/pull/935 + ## [0.4.27] - 2024-07-11 ### Changed diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 78cdf8268..ef6f2dc9f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -48,7 +48,7 @@ make build # executable: ./bin/yorkie You can set testing environment via Docker Compose. It is needed because integration tests require local applications like MongoDB. ```sh -docker-compose -f build/docker/docker-compose.yml up --build -d +docker compose -f build/docker/docker-compose.yml up --build -d make test ``` diff --git a/Makefile b/Makefile index a74241b41..b0ec6bc58 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -YORKIE_VERSION := 0.4.27 +YORKIE_VERSION := 0.5.0 GO_PROJECT = github.com/yorkie-team/yorkie diff --git a/README.md b/README.md index 8cf6aa5fd..96ba4da24 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,12 @@ [![CodeCov](https://img.shields.io/codecov/c/github/yorkie-team/yorkie)](https://codecov.io/gh/yorkie-team/yorkie) [![Godoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](https://godoc.org/github.com/yorkie-team/yorkie) -Yorkie is an open source document store for building collaborative editing applications. Yorkie uses JSON-like documents(CRDT) with optional types. +Yorkie is an open-source document store for building real-time collaborative applications. It uses JSON-like documents(CRDT) with optional types. Yorkie consists of three main components: Client, Document and Server. ``` - Client "A" (Go) Self-Hosted Server Or Cloud MongoDB or MemDB + Client "A" (Go) Server(Cloud or Self-Hosted) MongoDB or MemDB ┌───────────────────┐ ┌────────────────────────┐ ┌───────────┐ │ Document "D-1" │◄─Changes─►│ Project "P-1" │ │ Changes │ │ { a: 1, b: {} } │ │ ┌───────────────────┐ │◄─►│ Snapshots │ @@ -33,10 +33,13 @@ Yorkie consists of three main components: Client, Document and Server. └────────────────────┘ ``` -- Clients can have a replica of the document representing an application model locally on several devices. -- Each client can independently update the document on their local device, even while offline. -- When a network connection is available, the client figures out which changes need to be synced from one device to another, and brings them into the same state. -- If the document was changed concurrently on different devices, Yorkie automatically syncs the changes, so that every replica ends up in the same state with resolving conflict. +Key Features: + +- Clients: Clients can have a local replica of the document representing an application model on several devices. +- Offline Editing: Each client can independently update the document on their local device, even while offline. +- Synchronization: When a network connection is available, the client figures out which changes need to be synced from one device to another, and brings them into the same state. +- Conflict Resolution: If the document was changed concurrently on different devices, Yorkie automatically syncs the changes, so that every replica ends up in the same state with resolving conflicts. +- Database Integration: Yorkie supports MongoDB and MemDB as the underlying data storage. ## Documentation diff --git a/admin/client.go b/admin/client.go index a55426ba3..043f2ffca 100644 --- a/admin/client.go +++ b/admin/client.go @@ -360,6 +360,20 @@ func (c *Client) ListChangeSummaries( return summaries, nil } +// GetServerVersion gets the server version. +func (c *Client) GetServerVersion(ctx context.Context) (*types.VersionDetail, error) { + response, err := c.client.GetServerVersion(ctx, connect.NewRequest(&api.GetServerVersionRequest{})) + if err != nil { + return nil, err + } + + return &types.VersionDetail{ + YorkieVersion: response.Msg.YorkieVersion, + GoVersion: response.Msg.GoVersion, + BuildDate: response.Msg.BuildDate, + }, nil +} + /** * withShardKey returns a context with the given shard key in metadata. */ @@ -369,3 +383,30 @@ func withShardKey[T any](conn *connect.Request[T], keys ...string) *connect.Requ return conn } + +// DeleteAccount deletes the user's account. +func (c *Client) DeleteAccount(ctx context.Context, username, password string) error { + _, err := c.client.DeleteAccount(ctx, connect.NewRequest(&api.DeleteAccountRequest{ + Username: username, + Password: password, + })) + if err != nil { + return err + } + + return nil +} + +// ChangePassword changes the user's password. +func (c *Client) ChangePassword(ctx context.Context, username, password, newPassword string) error { + _, err := c.client.ChangePassword(ctx, connect.NewRequest(&api.ChangePasswordRequest{ + Username: username, + CurrentPassword: password, + NewPassword: newPassword, + })) + if err != nil { + return err + } + + return nil +} diff --git a/api/converter/from_pb.go b/api/converter/from_pb.go index b8c3dbdb5..a5cda6c09 100644 --- a/api/converter/from_pb.go +++ b/api/converter/from_pb.go @@ -257,6 +257,8 @@ func FromOperations(pbOps []*api.Operation) ([]operations.Operation, error) { op, err = fromTreeEdit(decoded.TreeEdit) case *api.Operation_TreeStyle_: op, err = fromTreeStyle(decoded.TreeStyle) + case *api.Operation_ArraySet_: + op, err = fromArraySet(decoded.ArraySet) default: return nil, ErrUnsupportedOperation } @@ -588,6 +590,31 @@ func fromTreeStyle(pbTreeStyle *api.Operation_TreeStyle) (*operations.TreeStyle, ), nil } +func fromArraySet(pbSetByIndex *api.Operation_ArraySet) (*operations.ArraySet, error) { + parentCreatedAt, err := fromTimeTicket(pbSetByIndex.ParentCreatedAt) + if err != nil { + return nil, err + } + createdAt, err := fromTimeTicket(pbSetByIndex.CreatedAt) + if err != nil { + return nil, err + } + elem, err := fromElement(pbSetByIndex.Value) + if err != nil { + return nil, err + } + executedAt, err := fromTimeTicket(pbSetByIndex.ExecutedAt) + if err != nil { + return nil, err + } + return operations.NewArraySet( + parentCreatedAt, + createdAt, + elem, + executedAt, + ), nil +} + func fromCreatedAtMapByActor( pbCreatedAtMapByActor map[string]*api.TimeTicket, ) (map[string]*time.Ticket, error) { @@ -632,18 +659,15 @@ func FromTreeNodes(pbNodes []*api.TreeNode) (*crdt.TreeNode, error) { } root := nodes[len(nodes)-1] + depthTable := make(map[int32]*crdt.TreeNode) + depthTable[pbNodes[len(nodes)-1].Depth] = nodes[len(nodes)-1] for i := len(nodes) - 2; i >= 0; i-- { - var parent *crdt.TreeNode - for j := i + 1; j < len(nodes); j++ { - if pbNodes[i].Depth-1 == pbNodes[j].Depth { - parent = nodes[j] - break - } - } + var parent *crdt.TreeNode = depthTable[pbNodes[i].Depth-1] if err := parent.Prepend(nodes[i]); err != nil { return nil, err } + depthTable[pbNodes[i].Depth] = nodes[i] } root.Index.UpdateDescendantsSize() diff --git a/api/converter/to_pb.go b/api/converter/to_pb.go index c605ce1f9..0057a9e94 100644 --- a/api/converter/to_pb.go +++ b/api/converter/to_pb.go @@ -234,6 +234,8 @@ func ToOperations(ops []operations.Operation) ([]*api.Operation, error) { pbOperation.Body, err = toTreeEdit(op) case *operations.TreeStyle: pbOperation.Body, err = toTreeStyle(op) + case *operations.ArraySet: + pbOperation.Body, err = toArraySet(op) default: return nil, ErrUnsupportedOperation } @@ -408,6 +410,22 @@ func toTreeStyle(style *operations.TreeStyle) (*api.Operation_TreeStyle_, error) }, nil } +func toArraySet(setByIndex *operations.ArraySet) (*api.Operation_ArraySet_, error) { + pbElem, err := toJSONElementSimple(setByIndex.Value()) + if err != nil { + return nil, err + } + + return &api.Operation_ArraySet_{ + ArraySet: &api.Operation_ArraySet{ + ParentCreatedAt: ToTimeTicket(setByIndex.ParentCreatedAt()), + CreatedAt: ToTimeTicket(setByIndex.CreatedAt()), + Value: pbElem, + ExecutedAt: ToTimeTicket(setByIndex.ExecutedAt()), + }, + }, nil +} + func toJSONElementSimple(elem crdt.Element) (*api.JSONElementSimple, error) { switch elem := elem.(type) { case *crdt.Object: diff --git a/api/docs/yorkie.base.yaml b/api/docs/yorkie.base.yaml index 2b7c76835..cc22f1f9f 100644 --- a/api/docs/yorkie.base.yaml +++ b/api/docs/yorkie.base.yaml @@ -2,7 +2,7 @@ openapi: 3.1.0 info: title: Yorkie description: "Yorkie is an open source document store for building collaborative editing applications." - version: v0.4.27 + version: v0.5.0 servers: - url: https://api.yorkie.dev description: Production server diff --git a/api/docs/yorkie/v1/admin.openapi.yaml b/api/docs/yorkie/v1/admin.openapi.yaml index 42a7132ec..8e5d7beca 100644 --- a/api/docs/yorkie/v1/admin.openapi.yaml +++ b/api/docs/yorkie/v1/admin.openapi.yaml @@ -3,13 +3,25 @@ info: description: Yorkie is an open source document store for building collaborative editing applications. title: Yorkie - version: v0.4.27 + version: v0.5.0 servers: - description: Production server url: https://api.yorkie.dev - description: Local server url: http://localhost:8080 paths: + /yorkie.v1.AdminService/ChangePassword: + post: + description: "" + requestBody: + $ref: '#/components/requestBodies/yorkie.v1.AdminService.ChangePassword.yorkie.v1.ChangePasswordRequest' + responses: + "200": + $ref: '#/components/responses/yorkie.v1.AdminService.ChangePassword.yorkie.v1.ChangePasswordResponse' + default: + $ref: '#/components/responses/connect.error' + tags: + - yorkie.v1.AdminService /yorkie.v1.AdminService/CreateProject: post: description: "" @@ -22,6 +34,18 @@ paths: $ref: '#/components/responses/connect.error' tags: - yorkie.v1.AdminService + /yorkie.v1.AdminService/DeleteAccount: + post: + description: "" + requestBody: + $ref: '#/components/requestBodies/yorkie.v1.AdminService.DeleteAccount.yorkie.v1.DeleteAccountRequest' + responses: + "200": + $ref: '#/components/responses/yorkie.v1.AdminService.DeleteAccount.yorkie.v1.DeleteAccountResponse' + default: + $ref: '#/components/responses/connect.error' + tags: + - yorkie.v1.AdminService /yorkie.v1.AdminService/GetDocument: post: description: "" @@ -58,6 +82,18 @@ paths: $ref: '#/components/responses/connect.error' tags: - yorkie.v1.AdminService + /yorkie.v1.AdminService/GetServerVersion: + post: + description: "" + requestBody: + $ref: '#/components/requestBodies/yorkie.v1.AdminService.GetServerVersion.yorkie.v1.GetServerVersionRequest' + responses: + "200": + $ref: '#/components/responses/yorkie.v1.AdminService.GetServerVersion.yorkie.v1.GetServerVersionResponse' + default: + $ref: '#/components/responses/connect.error' + tags: + - yorkie.v1.AdminService /yorkie.v1.AdminService/GetSnapshotMeta: post: description: "" @@ -168,6 +204,15 @@ paths: - yorkie.v1.AdminService components: requestBodies: + yorkie.v1.AdminService.ChangePassword.yorkie.v1.ChangePasswordRequest: + content: + application/json: + schema: + $ref: '#/components/schemas/yorkie.v1.ChangePasswordRequest' + application/proto: + schema: + $ref: '#/components/schemas/yorkie.v1.ChangePasswordRequest' + required: true yorkie.v1.AdminService.CreateProject.yorkie.v1.CreateProjectRequest: content: application/json: @@ -177,6 +222,15 @@ components: schema: $ref: '#/components/schemas/yorkie.v1.CreateProjectRequest' required: true + yorkie.v1.AdminService.DeleteAccount.yorkie.v1.DeleteAccountRequest: + content: + application/json: + schema: + $ref: '#/components/schemas/yorkie.v1.DeleteAccountRequest' + application/proto: + schema: + $ref: '#/components/schemas/yorkie.v1.DeleteAccountRequest' + required: true yorkie.v1.AdminService.GetDocument.yorkie.v1.GetDocumentRequest: content: application/json: @@ -204,6 +258,15 @@ components: schema: $ref: '#/components/schemas/yorkie.v1.GetProjectRequest' required: true + yorkie.v1.AdminService.GetServerVersion.yorkie.v1.GetServerVersionRequest: + content: + application/json: + schema: + $ref: '#/components/schemas/yorkie.v1.GetServerVersionRequest' + application/proto: + schema: + $ref: '#/components/schemas/yorkie.v1.GetServerVersionRequest' + required: true yorkie.v1.AdminService.GetSnapshotMeta.yorkie.v1.GetSnapshotMetaRequest: content: application/json: @@ -295,6 +358,15 @@ components: schema: $ref: '#/components/schemas/connect.error' description: "" + yorkie.v1.AdminService.ChangePassword.yorkie.v1.ChangePasswordResponse: + content: + application/json: + schema: + $ref: '#/components/schemas/yorkie.v1.ChangePasswordResponse' + application/proto: + schema: + $ref: '#/components/schemas/yorkie.v1.ChangePasswordResponse' + description: "" yorkie.v1.AdminService.CreateProject.yorkie.v1.CreateProjectResponse: content: application/json: @@ -304,6 +376,15 @@ components: schema: $ref: '#/components/schemas/yorkie.v1.CreateProjectResponse' description: "" + yorkie.v1.AdminService.DeleteAccount.yorkie.v1.DeleteAccountResponse: + content: + application/json: + schema: + $ref: '#/components/schemas/yorkie.v1.DeleteAccountResponse' + application/proto: + schema: + $ref: '#/components/schemas/yorkie.v1.DeleteAccountResponse' + description: "" yorkie.v1.AdminService.GetDocument.yorkie.v1.GetDocumentResponse: content: application/json: @@ -331,6 +412,15 @@ components: schema: $ref: '#/components/schemas/yorkie.v1.GetProjectResponse' description: "" + yorkie.v1.AdminService.GetServerVersion.yorkie.v1.GetServerVersionResponse: + content: + application/json: + schema: + $ref: '#/components/schemas/yorkie.v1.GetServerVersionResponse' + application/proto: + schema: + $ref: '#/components/schemas/yorkie.v1.GetServerVersionResponse' + description: "" yorkie.v1.AdminService.GetSnapshotMeta.yorkie.v1.GetSnapshotMetaResponse: content: application/json: @@ -617,6 +707,32 @@ components: type: object title: ChangeID type: object + yorkie.v1.ChangePasswordRequest: + additionalProperties: false + description: "" + properties: + currentPassword: + additionalProperties: false + description: "" + title: current_password + type: string + newPassword: + additionalProperties: false + description: "" + title: new_password + type: string + username: + additionalProperties: false + description: "" + title: username + type: string + title: ChangePasswordRequest + type: object + yorkie.v1.ChangePasswordResponse: + additionalProperties: false + description: "" + title: ChangePasswordResponse + type: object yorkie.v1.CreateProjectRequest: additionalProperties: false description: "" @@ -640,6 +756,27 @@ components: type: object title: CreateProjectResponse type: object + yorkie.v1.DeleteAccountRequest: + additionalProperties: false + description: "" + properties: + password: + additionalProperties: false + description: "" + title: password + type: string + username: + additionalProperties: false + description: "" + title: username + type: string + title: DeleteAccountRequest + type: object + yorkie.v1.DeleteAccountResponse: + additionalProperties: false + description: "" + title: DeleteAccountResponse + type: object yorkie.v1.DocumentSummary: additionalProperties: false description: "" @@ -718,6 +855,11 @@ components: type: string title: document_keys type: array + includeSnapshot: + additionalProperties: false + description: "" + title: include_snapshot + type: boolean projectName: additionalProperties: false description: "" @@ -762,6 +904,32 @@ components: type: object title: GetProjectResponse type: object + yorkie.v1.GetServerVersionRequest: + additionalProperties: false + description: "" + title: GetServerVersionRequest + type: object + yorkie.v1.GetServerVersionResponse: + additionalProperties: false + description: "" + properties: + buildDate: + additionalProperties: false + description: "" + title: build_date + type: string + goVersion: + additionalProperties: false + description: "" + title: go_version + type: string + yorkieVersion: + additionalProperties: false + description: "" + title: yorkie_version + type: string + title: GetServerVersionResponse + type: object yorkie.v1.GetSnapshotMetaRequest: additionalProperties: false description: "" @@ -1015,6 +1183,12 @@ components: description: "" title: add type: object + arraySet: + $ref: '#/components/schemas/yorkie.v1.Operation.ArraySet' + additionalProperties: false + description: "" + title: array_set + type: object edit: $ref: '#/components/schemas/yorkie.v1.Operation.Edit' additionalProperties: false @@ -1101,6 +1275,36 @@ components: type: object title: Add type: object + yorkie.v1.Operation.ArraySet: + additionalProperties: false + description: "" + properties: + createdAt: + $ref: '#/components/schemas/yorkie.v1.TimeTicket' + additionalProperties: false + description: "" + title: created_at + type: object + executedAt: + $ref: '#/components/schemas/yorkie.v1.TimeTicket' + additionalProperties: false + description: "" + title: executed_at + type: object + parentCreatedAt: + $ref: '#/components/schemas/yorkie.v1.TimeTicket' + additionalProperties: false + description: "" + title: parent_created_at + type: object + value: + $ref: '#/components/schemas/yorkie.v1.JSONElementSimple' + additionalProperties: false + description: "" + title: value + type: object + title: ArraySet + type: object yorkie.v1.Operation.Edit: additionalProperties: false description: "" diff --git a/api/docs/yorkie/v1/resources.openapi.yaml b/api/docs/yorkie/v1/resources.openapi.yaml index cfdb7cd3c..98788814c 100644 --- a/api/docs/yorkie/v1/resources.openapi.yaml +++ b/api/docs/yorkie/v1/resources.openapi.yaml @@ -3,7 +3,7 @@ info: description: Yorkie is an open source document store for building collaborative editing applications. title: Yorkie - version: v0.4.27 + version: v0.5.0 servers: - description: Production server url: https://api.yorkie.dev @@ -704,6 +704,12 @@ components: description: "" title: add type: object + arraySet: + $ref: '#/components/schemas/yorkie.v1.Operation.ArraySet' + additionalProperties: false + description: "" + title: array_set + type: object edit: $ref: '#/components/schemas/yorkie.v1.Operation.Edit' additionalProperties: false @@ -790,6 +796,36 @@ components: type: object title: Add type: object + yorkie.v1.Operation.ArraySet: + additionalProperties: false + description: "" + properties: + createdAt: + $ref: '#/components/schemas/yorkie.v1.TimeTicket' + additionalProperties: false + description: "" + title: created_at + type: object + executedAt: + $ref: '#/components/schemas/yorkie.v1.TimeTicket' + additionalProperties: false + description: "" + title: executed_at + type: object + parentCreatedAt: + $ref: '#/components/schemas/yorkie.v1.TimeTicket' + additionalProperties: false + description: "" + title: parent_created_at + type: object + value: + $ref: '#/components/schemas/yorkie.v1.JSONElementSimple' + additionalProperties: false + description: "" + title: value + type: object + title: ArraySet + type: object yorkie.v1.Operation.Edit: additionalProperties: false description: "" diff --git a/api/docs/yorkie/v1/yorkie.openapi.yaml b/api/docs/yorkie/v1/yorkie.openapi.yaml index 0971a51e1..a6a2365de 100644 --- a/api/docs/yorkie/v1/yorkie.openapi.yaml +++ b/api/docs/yorkie/v1/yorkie.openapi.yaml @@ -3,7 +3,7 @@ info: description: Yorkie is an open source document store for building collaborative editing applications. title: Yorkie - version: v0.4.27 + version: v0.5.0 servers: - description: Production server url: https://api.yorkie.dev @@ -688,6 +688,12 @@ components: description: "" title: add type: object + arraySet: + $ref: '#/components/schemas/yorkie.v1.Operation.ArraySet' + additionalProperties: false + description: "" + title: array_set + type: object edit: $ref: '#/components/schemas/yorkie.v1.Operation.Edit' additionalProperties: false @@ -774,6 +780,36 @@ components: type: object title: Add type: object + yorkie.v1.Operation.ArraySet: + additionalProperties: false + description: "" + properties: + createdAt: + $ref: '#/components/schemas/yorkie.v1.TimeTicket' + additionalProperties: false + description: "" + title: created_at + type: object + executedAt: + $ref: '#/components/schemas/yorkie.v1.TimeTicket' + additionalProperties: false + description: "" + title: executed_at + type: object + parentCreatedAt: + $ref: '#/components/schemas/yorkie.v1.TimeTicket' + additionalProperties: false + description: "" + title: parent_created_at + type: object + value: + $ref: '#/components/schemas/yorkie.v1.JSONElementSimple' + additionalProperties: false + description: "" + title: value + type: object + title: ArraySet + type: object yorkie.v1.Operation.Edit: additionalProperties: false description: "" diff --git a/api/types/event.go b/api/types/event.go index f0d2b160b..3d0909d87 100644 --- a/api/types/event.go +++ b/api/types/event.go @@ -26,3 +26,8 @@ type DocEventBody struct { Topic string Payload []byte } + +// PayloadLen returns the size of the payload. +func (b *DocEventBody) PayloadLen() int { + return len(b.Payload) +} diff --git a/api/types/signup_fields.go b/api/types/user_fields.go similarity index 83% rename from api/types/signup_fields.go rename to api/types/user_fields.go index 7c2769680..3175c224b 100644 --- a/api/types/signup_fields.go +++ b/api/types/user_fields.go @@ -21,8 +21,8 @@ import ( "github.com/yorkie-team/yorkie/internal/validation" ) -// SignupFields is a set of fields that use to sign up to yorkie server. -type SignupFields struct { +// UserFields is a set of fields that use to sign up or change password to yorkie server. +type UserFields struct { // Username is the name of user. Username *string `bson:"username" validate:"required,min=2,max=30,slug"` @@ -30,7 +30,7 @@ type SignupFields struct { Password *string `bson:"password" validate:"required,min=8,max=30,alpha_num_special"` } -// Validate validates the SignupFields. -func (i *SignupFields) Validate() error { +// Validate validates the UserFields. +func (i *UserFields) Validate() error { return validation.ValidateStruct(i) } diff --git a/api/types/signup_fields_test.go b/api/types/user_fields_test.go similarity index 89% rename from api/types/signup_fields_test.go rename to api/types/user_fields_test.go index 19c1862f6..15e30339a 100644 --- a/api/types/signup_fields_test.go +++ b/api/types/user_fields_test.go @@ -31,56 +31,56 @@ func TestSignupFields(t *testing.T) { t.Run("password validation test", func(t *testing.T) { validUsername := "test" validPassword := "pass123!" - fields := &types.SignupFields{ + fields := &types.UserFields{ Username: &validUsername, Password: &validPassword, } assert.NoError(t, fields.Validate()) invalidPassword := "1234" - fields = &types.SignupFields{ + fields = &types.UserFields{ Username: &validUsername, Password: &invalidPassword, } assert.ErrorAs(t, fields.Validate(), &structError) invalidPassword = "abcd" - fields = &types.SignupFields{ + fields = &types.UserFields{ Username: &validUsername, Password: &invalidPassword, } assert.ErrorAs(t, fields.Validate(), &structError) invalidPassword = "!@#$" - fields = &types.SignupFields{ + fields = &types.UserFields{ Username: &validUsername, Password: &invalidPassword, } assert.ErrorAs(t, fields.Validate(), &structError) invalidPassword = "abcd1234" - fields = &types.SignupFields{ + fields = &types.UserFields{ Username: &validUsername, Password: &invalidPassword, } assert.ErrorAs(t, fields.Validate(), &structError) invalidPassword = "abcd!@#$" - fields = &types.SignupFields{ + fields = &types.UserFields{ Username: &validUsername, Password: &invalidPassword, } assert.ErrorAs(t, fields.Validate(), &structError) invalidPassword = "1234!@#$" - fields = &types.SignupFields{ + fields = &types.UserFields{ Username: &validUsername, Password: &invalidPassword, } assert.ErrorAs(t, fields.Validate(), &structError) invalidPassword = "abcd1234!@abcd1234!@abcd1234!@1" - fields = &types.SignupFields{ + fields = &types.UserFields{ Username: &validUsername, Password: &invalidPassword, } diff --git a/api/types/version_info.go b/api/types/version_info.go new file mode 100644 index 000000000..f7e083ba5 --- /dev/null +++ b/api/types/version_info.go @@ -0,0 +1,22 @@ +package types + +// VersionInfo represents information of version. +type VersionInfo struct { + // ClientVersion is the yorkie cli version. + ClientVersion *VersionDetail `json:"clientVersion,omitempty" yaml:"clientVersion,omitempty"` + + // ServerVersion is the yorkie server version. + ServerVersion *VersionDetail `json:"serverVersion,omitempty" yaml:"serverVersion,omitempty"` +} + +// VersionDetail represents detail information of version. +type VersionDetail struct { + // YorkieVersion + YorkieVersion string `json:"yorkieVersion" yaml:"yorkieVersion"` + + // GoVersion + GoVersion string `json:"goVersion" yaml:"goVersion"` + + // BuildDate + BuildDate string `json:"buildDate" yaml:"buildDate"` +} diff --git a/api/yorkie/v1/admin.pb.go b/api/yorkie/v1/admin.pb.go index 1b88673d7..77a69f918 100644 --- a/api/yorkie/v1/admin.pb.go +++ b/api/yorkie/v1/admin.pb.go @@ -239,6 +239,200 @@ func (x *LogInResponse) GetToken() string { return "" } +type DeleteAccountRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` + Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` +} + +func (x *DeleteAccountRequest) Reset() { + *x = DeleteAccountRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_yorkie_v1_admin_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteAccountRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteAccountRequest) ProtoMessage() {} + +func (x *DeleteAccountRequest) ProtoReflect() protoreflect.Message { + mi := &file_yorkie_v1_admin_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteAccountRequest.ProtoReflect.Descriptor instead. +func (*DeleteAccountRequest) Descriptor() ([]byte, []int) { + return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{4} +} + +func (x *DeleteAccountRequest) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +func (x *DeleteAccountRequest) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +type DeleteAccountResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DeleteAccountResponse) Reset() { + *x = DeleteAccountResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_yorkie_v1_admin_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteAccountResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteAccountResponse) ProtoMessage() {} + +func (x *DeleteAccountResponse) ProtoReflect() protoreflect.Message { + mi := &file_yorkie_v1_admin_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteAccountResponse.ProtoReflect.Descriptor instead. +func (*DeleteAccountResponse) Descriptor() ([]byte, []int) { + return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{5} +} + +type ChangePasswordRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` + CurrentPassword string `protobuf:"bytes,2,opt,name=current_password,json=currentPassword,proto3" json:"current_password,omitempty"` + NewPassword string `protobuf:"bytes,3,opt,name=new_password,json=newPassword,proto3" json:"new_password,omitempty"` +} + +func (x *ChangePasswordRequest) Reset() { + *x = ChangePasswordRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_yorkie_v1_admin_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ChangePasswordRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChangePasswordRequest) ProtoMessage() {} + +func (x *ChangePasswordRequest) ProtoReflect() protoreflect.Message { + mi := &file_yorkie_v1_admin_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ChangePasswordRequest.ProtoReflect.Descriptor instead. +func (*ChangePasswordRequest) Descriptor() ([]byte, []int) { + return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{6} +} + +func (x *ChangePasswordRequest) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +func (x *ChangePasswordRequest) GetCurrentPassword() string { + if x != nil { + return x.CurrentPassword + } + return "" +} + +func (x *ChangePasswordRequest) GetNewPassword() string { + if x != nil { + return x.NewPassword + } + return "" +} + +type ChangePasswordResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ChangePasswordResponse) Reset() { + *x = ChangePasswordResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_yorkie_v1_admin_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ChangePasswordResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChangePasswordResponse) ProtoMessage() {} + +func (x *ChangePasswordResponse) ProtoReflect() protoreflect.Message { + mi := &file_yorkie_v1_admin_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ChangePasswordResponse.ProtoReflect.Descriptor instead. +func (*ChangePasswordResponse) Descriptor() ([]byte, []int) { + return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{7} +} + type CreateProjectRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -250,7 +444,7 @@ type CreateProjectRequest struct { func (x *CreateProjectRequest) Reset() { *x = CreateProjectRequest{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_admin_proto_msgTypes[4] + mi := &file_yorkie_v1_admin_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -263,7 +457,7 @@ func (x *CreateProjectRequest) String() string { func (*CreateProjectRequest) ProtoMessage() {} func (x *CreateProjectRequest) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_admin_proto_msgTypes[4] + mi := &file_yorkie_v1_admin_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -276,7 +470,7 @@ func (x *CreateProjectRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateProjectRequest.ProtoReflect.Descriptor instead. func (*CreateProjectRequest) Descriptor() ([]byte, []int) { - return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{4} + return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{8} } func (x *CreateProjectRequest) GetName() string { @@ -297,7 +491,7 @@ type CreateProjectResponse struct { func (x *CreateProjectResponse) Reset() { *x = CreateProjectResponse{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_admin_proto_msgTypes[5] + mi := &file_yorkie_v1_admin_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -310,7 +504,7 @@ func (x *CreateProjectResponse) String() string { func (*CreateProjectResponse) ProtoMessage() {} func (x *CreateProjectResponse) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_admin_proto_msgTypes[5] + mi := &file_yorkie_v1_admin_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -323,7 +517,7 @@ func (x *CreateProjectResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateProjectResponse.ProtoReflect.Descriptor instead. func (*CreateProjectResponse) Descriptor() ([]byte, []int) { - return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{5} + return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{9} } func (x *CreateProjectResponse) GetProject() *Project { @@ -344,7 +538,7 @@ type GetProjectRequest struct { func (x *GetProjectRequest) Reset() { *x = GetProjectRequest{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_admin_proto_msgTypes[6] + mi := &file_yorkie_v1_admin_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -357,7 +551,7 @@ func (x *GetProjectRequest) String() string { func (*GetProjectRequest) ProtoMessage() {} func (x *GetProjectRequest) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_admin_proto_msgTypes[6] + mi := &file_yorkie_v1_admin_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -370,7 +564,7 @@ func (x *GetProjectRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProjectRequest.ProtoReflect.Descriptor instead. func (*GetProjectRequest) Descriptor() ([]byte, []int) { - return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{6} + return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{10} } func (x *GetProjectRequest) GetName() string { @@ -391,7 +585,7 @@ type GetProjectResponse struct { func (x *GetProjectResponse) Reset() { *x = GetProjectResponse{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_admin_proto_msgTypes[7] + mi := &file_yorkie_v1_admin_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -404,7 +598,7 @@ func (x *GetProjectResponse) String() string { func (*GetProjectResponse) ProtoMessage() {} func (x *GetProjectResponse) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_admin_proto_msgTypes[7] + mi := &file_yorkie_v1_admin_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -417,7 +611,7 @@ func (x *GetProjectResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetProjectResponse.ProtoReflect.Descriptor instead. func (*GetProjectResponse) Descriptor() ([]byte, []int) { - return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{7} + return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{11} } func (x *GetProjectResponse) GetProject() *Project { @@ -436,7 +630,7 @@ type ListProjectsRequest struct { func (x *ListProjectsRequest) Reset() { *x = ListProjectsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_admin_proto_msgTypes[8] + mi := &file_yorkie_v1_admin_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -449,7 +643,7 @@ func (x *ListProjectsRequest) String() string { func (*ListProjectsRequest) ProtoMessage() {} func (x *ListProjectsRequest) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_admin_proto_msgTypes[8] + mi := &file_yorkie_v1_admin_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -462,7 +656,7 @@ func (x *ListProjectsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProjectsRequest.ProtoReflect.Descriptor instead. func (*ListProjectsRequest) Descriptor() ([]byte, []int) { - return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{8} + return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{12} } type ListProjectsResponse struct { @@ -476,7 +670,7 @@ type ListProjectsResponse struct { func (x *ListProjectsResponse) Reset() { *x = ListProjectsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_admin_proto_msgTypes[9] + mi := &file_yorkie_v1_admin_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -489,7 +683,7 @@ func (x *ListProjectsResponse) String() string { func (*ListProjectsResponse) ProtoMessage() {} func (x *ListProjectsResponse) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_admin_proto_msgTypes[9] + mi := &file_yorkie_v1_admin_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -502,7 +696,7 @@ func (x *ListProjectsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProjectsResponse.ProtoReflect.Descriptor instead. func (*ListProjectsResponse) Descriptor() ([]byte, []int) { - return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{9} + return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{13} } func (x *ListProjectsResponse) GetProjects() []*Project { @@ -524,7 +718,7 @@ type UpdateProjectRequest struct { func (x *UpdateProjectRequest) Reset() { *x = UpdateProjectRequest{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_admin_proto_msgTypes[10] + mi := &file_yorkie_v1_admin_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -537,7 +731,7 @@ func (x *UpdateProjectRequest) String() string { func (*UpdateProjectRequest) ProtoMessage() {} func (x *UpdateProjectRequest) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_admin_proto_msgTypes[10] + mi := &file_yorkie_v1_admin_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -550,7 +744,7 @@ func (x *UpdateProjectRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateProjectRequest.ProtoReflect.Descriptor instead. func (*UpdateProjectRequest) Descriptor() ([]byte, []int) { - return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{10} + return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{14} } func (x *UpdateProjectRequest) GetId() string { @@ -578,7 +772,7 @@ type UpdateProjectResponse struct { func (x *UpdateProjectResponse) Reset() { *x = UpdateProjectResponse{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_admin_proto_msgTypes[11] + mi := &file_yorkie_v1_admin_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -591,7 +785,7 @@ func (x *UpdateProjectResponse) String() string { func (*UpdateProjectResponse) ProtoMessage() {} func (x *UpdateProjectResponse) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_admin_proto_msgTypes[11] + mi := &file_yorkie_v1_admin_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -604,7 +798,7 @@ func (x *UpdateProjectResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateProjectResponse.ProtoReflect.Descriptor instead. func (*UpdateProjectResponse) Descriptor() ([]byte, []int) { - return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{11} + return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{15} } func (x *UpdateProjectResponse) GetProject() *Project { @@ -629,7 +823,7 @@ type ListDocumentsRequest struct { func (x *ListDocumentsRequest) Reset() { *x = ListDocumentsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_admin_proto_msgTypes[12] + mi := &file_yorkie_v1_admin_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -642,7 +836,7 @@ func (x *ListDocumentsRequest) String() string { func (*ListDocumentsRequest) ProtoMessage() {} func (x *ListDocumentsRequest) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_admin_proto_msgTypes[12] + mi := &file_yorkie_v1_admin_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -655,7 +849,7 @@ func (x *ListDocumentsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListDocumentsRequest.ProtoReflect.Descriptor instead. func (*ListDocumentsRequest) Descriptor() ([]byte, []int) { - return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{12} + return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{16} } func (x *ListDocumentsRequest) GetProjectName() string { @@ -704,7 +898,7 @@ type ListDocumentsResponse struct { func (x *ListDocumentsResponse) Reset() { *x = ListDocumentsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_admin_proto_msgTypes[13] + mi := &file_yorkie_v1_admin_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -717,7 +911,7 @@ func (x *ListDocumentsResponse) String() string { func (*ListDocumentsResponse) ProtoMessage() {} func (x *ListDocumentsResponse) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_admin_proto_msgTypes[13] + mi := &file_yorkie_v1_admin_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -730,7 +924,7 @@ func (x *ListDocumentsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListDocumentsResponse.ProtoReflect.Descriptor instead. func (*ListDocumentsResponse) Descriptor() ([]byte, []int) { - return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{13} + return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{17} } func (x *ListDocumentsResponse) GetDocuments() []*DocumentSummary { @@ -752,7 +946,7 @@ type GetDocumentRequest struct { func (x *GetDocumentRequest) Reset() { *x = GetDocumentRequest{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_admin_proto_msgTypes[14] + mi := &file_yorkie_v1_admin_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -765,7 +959,7 @@ func (x *GetDocumentRequest) String() string { func (*GetDocumentRequest) ProtoMessage() {} func (x *GetDocumentRequest) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_admin_proto_msgTypes[14] + mi := &file_yorkie_v1_admin_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -778,7 +972,7 @@ func (x *GetDocumentRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDocumentRequest.ProtoReflect.Descriptor instead. func (*GetDocumentRequest) Descriptor() ([]byte, []int) { - return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{14} + return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{18} } func (x *GetDocumentRequest) GetProjectName() string { @@ -806,7 +1000,7 @@ type GetDocumentResponse struct { func (x *GetDocumentResponse) Reset() { *x = GetDocumentResponse{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_admin_proto_msgTypes[15] + mi := &file_yorkie_v1_admin_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -819,7 +1013,7 @@ func (x *GetDocumentResponse) String() string { func (*GetDocumentResponse) ProtoMessage() {} func (x *GetDocumentResponse) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_admin_proto_msgTypes[15] + mi := &file_yorkie_v1_admin_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -832,7 +1026,7 @@ func (x *GetDocumentResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDocumentResponse.ProtoReflect.Descriptor instead. func (*GetDocumentResponse) Descriptor() ([]byte, []int) { - return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{15} + return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{19} } func (x *GetDocumentResponse) GetDocument() *DocumentSummary { @@ -847,14 +1041,15 @@ type GetDocumentsRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ProjectName string `protobuf:"bytes,1,opt,name=project_name,json=projectName,proto3" json:"project_name,omitempty"` - DocumentKeys []string `protobuf:"bytes,2,rep,name=document_keys,json=documentKeys,proto3" json:"document_keys,omitempty"` + ProjectName string `protobuf:"bytes,1,opt,name=project_name,json=projectName,proto3" json:"project_name,omitempty"` + DocumentKeys []string `protobuf:"bytes,2,rep,name=document_keys,json=documentKeys,proto3" json:"document_keys,omitempty"` + IncludeSnapshot bool `protobuf:"varint,3,opt,name=include_snapshot,json=includeSnapshot,proto3" json:"include_snapshot,omitempty"` } func (x *GetDocumentsRequest) Reset() { *x = GetDocumentsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_admin_proto_msgTypes[16] + mi := &file_yorkie_v1_admin_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -867,7 +1062,7 @@ func (x *GetDocumentsRequest) String() string { func (*GetDocumentsRequest) ProtoMessage() {} func (x *GetDocumentsRequest) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_admin_proto_msgTypes[16] + mi := &file_yorkie_v1_admin_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -880,7 +1075,7 @@ func (x *GetDocumentsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDocumentsRequest.ProtoReflect.Descriptor instead. func (*GetDocumentsRequest) Descriptor() ([]byte, []int) { - return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{16} + return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{20} } func (x *GetDocumentsRequest) GetProjectName() string { @@ -897,6 +1092,13 @@ func (x *GetDocumentsRequest) GetDocumentKeys() []string { return nil } +func (x *GetDocumentsRequest) GetIncludeSnapshot() bool { + if x != nil { + return x.IncludeSnapshot + } + return false +} + type GetDocumentsResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -908,7 +1110,7 @@ type GetDocumentsResponse struct { func (x *GetDocumentsResponse) Reset() { *x = GetDocumentsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_admin_proto_msgTypes[17] + mi := &file_yorkie_v1_admin_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -921,7 +1123,7 @@ func (x *GetDocumentsResponse) String() string { func (*GetDocumentsResponse) ProtoMessage() {} func (x *GetDocumentsResponse) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_admin_proto_msgTypes[17] + mi := &file_yorkie_v1_admin_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -934,7 +1136,7 @@ func (x *GetDocumentsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetDocumentsResponse.ProtoReflect.Descriptor instead. func (*GetDocumentsResponse) Descriptor() ([]byte, []int) { - return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{17} + return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{21} } func (x *GetDocumentsResponse) GetDocuments() []*DocumentSummary { @@ -957,7 +1159,7 @@ type RemoveDocumentByAdminRequest struct { func (x *RemoveDocumentByAdminRequest) Reset() { *x = RemoveDocumentByAdminRequest{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_admin_proto_msgTypes[18] + mi := &file_yorkie_v1_admin_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -970,7 +1172,7 @@ func (x *RemoveDocumentByAdminRequest) String() string { func (*RemoveDocumentByAdminRequest) ProtoMessage() {} func (x *RemoveDocumentByAdminRequest) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_admin_proto_msgTypes[18] + mi := &file_yorkie_v1_admin_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -983,7 +1185,7 @@ func (x *RemoveDocumentByAdminRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveDocumentByAdminRequest.ProtoReflect.Descriptor instead. func (*RemoveDocumentByAdminRequest) Descriptor() ([]byte, []int) { - return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{18} + return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{22} } func (x *RemoveDocumentByAdminRequest) GetProjectName() string { @@ -1016,7 +1218,7 @@ type RemoveDocumentByAdminResponse struct { func (x *RemoveDocumentByAdminResponse) Reset() { *x = RemoveDocumentByAdminResponse{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_admin_proto_msgTypes[19] + mi := &file_yorkie_v1_admin_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1029,7 +1231,7 @@ func (x *RemoveDocumentByAdminResponse) String() string { func (*RemoveDocumentByAdminResponse) ProtoMessage() {} func (x *RemoveDocumentByAdminResponse) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_admin_proto_msgTypes[19] + mi := &file_yorkie_v1_admin_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1042,7 +1244,7 @@ func (x *RemoveDocumentByAdminResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveDocumentByAdminResponse.ProtoReflect.Descriptor instead. func (*RemoveDocumentByAdminResponse) Descriptor() ([]byte, []int) { - return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{19} + return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{23} } type GetSnapshotMetaRequest struct { @@ -1058,7 +1260,7 @@ type GetSnapshotMetaRequest struct { func (x *GetSnapshotMetaRequest) Reset() { *x = GetSnapshotMetaRequest{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_admin_proto_msgTypes[20] + mi := &file_yorkie_v1_admin_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1071,7 +1273,7 @@ func (x *GetSnapshotMetaRequest) String() string { func (*GetSnapshotMetaRequest) ProtoMessage() {} func (x *GetSnapshotMetaRequest) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_admin_proto_msgTypes[20] + mi := &file_yorkie_v1_admin_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1084,7 +1286,7 @@ func (x *GetSnapshotMetaRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSnapshotMetaRequest.ProtoReflect.Descriptor instead. func (*GetSnapshotMetaRequest) Descriptor() ([]byte, []int) { - return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{20} + return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{24} } func (x *GetSnapshotMetaRequest) GetProjectName() string { @@ -1121,7 +1323,7 @@ type GetSnapshotMetaResponse struct { func (x *GetSnapshotMetaResponse) Reset() { *x = GetSnapshotMetaResponse{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_admin_proto_msgTypes[21] + mi := &file_yorkie_v1_admin_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1134,7 +1336,7 @@ func (x *GetSnapshotMetaResponse) String() string { func (*GetSnapshotMetaResponse) ProtoMessage() {} func (x *GetSnapshotMetaResponse) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_admin_proto_msgTypes[21] + mi := &file_yorkie_v1_admin_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1147,7 +1349,7 @@ func (x *GetSnapshotMetaResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSnapshotMetaResponse.ProtoReflect.Descriptor instead. func (*GetSnapshotMetaResponse) Descriptor() ([]byte, []int) { - return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{21} + return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{25} } func (x *GetSnapshotMetaResponse) GetSnapshot() []byte { @@ -1184,7 +1386,7 @@ type SearchDocumentsRequest struct { func (x *SearchDocumentsRequest) Reset() { *x = SearchDocumentsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_admin_proto_msgTypes[22] + mi := &file_yorkie_v1_admin_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1197,7 +1399,7 @@ func (x *SearchDocumentsRequest) String() string { func (*SearchDocumentsRequest) ProtoMessage() {} func (x *SearchDocumentsRequest) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_admin_proto_msgTypes[22] + mi := &file_yorkie_v1_admin_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1210,7 +1412,7 @@ func (x *SearchDocumentsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SearchDocumentsRequest.ProtoReflect.Descriptor instead. func (*SearchDocumentsRequest) Descriptor() ([]byte, []int) { - return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{22} + return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{26} } func (x *SearchDocumentsRequest) GetProjectName() string { @@ -1246,7 +1448,7 @@ type SearchDocumentsResponse struct { func (x *SearchDocumentsResponse) Reset() { *x = SearchDocumentsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_admin_proto_msgTypes[23] + mi := &file_yorkie_v1_admin_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1259,7 +1461,7 @@ func (x *SearchDocumentsResponse) String() string { func (*SearchDocumentsResponse) ProtoMessage() {} func (x *SearchDocumentsResponse) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_admin_proto_msgTypes[23] + mi := &file_yorkie_v1_admin_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1272,7 +1474,7 @@ func (x *SearchDocumentsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SearchDocumentsResponse.ProtoReflect.Descriptor instead. func (*SearchDocumentsResponse) Descriptor() ([]byte, []int) { - return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{23} + return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{27} } func (x *SearchDocumentsResponse) GetTotalCount() int32 { @@ -1304,7 +1506,7 @@ type ListChangesRequest struct { func (x *ListChangesRequest) Reset() { *x = ListChangesRequest{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_admin_proto_msgTypes[24] + mi := &file_yorkie_v1_admin_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1317,7 +1519,7 @@ func (x *ListChangesRequest) String() string { func (*ListChangesRequest) ProtoMessage() {} func (x *ListChangesRequest) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_admin_proto_msgTypes[24] + mi := &file_yorkie_v1_admin_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1330,7 +1532,7 @@ func (x *ListChangesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListChangesRequest.ProtoReflect.Descriptor instead. func (*ListChangesRequest) Descriptor() ([]byte, []int) { - return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{24} + return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{28} } func (x *ListChangesRequest) GetProjectName() string { @@ -1379,7 +1581,7 @@ type ListChangesResponse struct { func (x *ListChangesResponse) Reset() { *x = ListChangesResponse{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_admin_proto_msgTypes[25] + mi := &file_yorkie_v1_admin_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1392,7 +1594,7 @@ func (x *ListChangesResponse) String() string { func (*ListChangesResponse) ProtoMessage() {} func (x *ListChangesResponse) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_admin_proto_msgTypes[25] + mi := &file_yorkie_v1_admin_proto_msgTypes[29] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1405,7 +1607,7 @@ func (x *ListChangesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListChangesResponse.ProtoReflect.Descriptor instead. func (*ListChangesResponse) Descriptor() ([]byte, []int) { - return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{25} + return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{29} } func (x *ListChangesResponse) GetChanges() []*Change { @@ -1415,6 +1617,107 @@ func (x *ListChangesResponse) GetChanges() []*Change { return nil } +type GetServerVersionRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetServerVersionRequest) Reset() { + *x = GetServerVersionRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_yorkie_v1_admin_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetServerVersionRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetServerVersionRequest) ProtoMessage() {} + +func (x *GetServerVersionRequest) ProtoReflect() protoreflect.Message { + mi := &file_yorkie_v1_admin_proto_msgTypes[30] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetServerVersionRequest.ProtoReflect.Descriptor instead. +func (*GetServerVersionRequest) Descriptor() ([]byte, []int) { + return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{30} +} + +type GetServerVersionResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + YorkieVersion string `protobuf:"bytes,1,opt,name=yorkie_version,json=yorkieVersion,proto3" json:"yorkie_version,omitempty"` + GoVersion string `protobuf:"bytes,2,opt,name=go_version,json=goVersion,proto3" json:"go_version,omitempty"` + BuildDate string `protobuf:"bytes,3,opt,name=build_date,json=buildDate,proto3" json:"build_date,omitempty"` +} + +func (x *GetServerVersionResponse) Reset() { + *x = GetServerVersionResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_yorkie_v1_admin_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetServerVersionResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetServerVersionResponse) ProtoMessage() {} + +func (x *GetServerVersionResponse) ProtoReflect() protoreflect.Message { + mi := &file_yorkie_v1_admin_proto_msgTypes[31] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetServerVersionResponse.ProtoReflect.Descriptor instead. +func (*GetServerVersionResponse) Descriptor() ([]byte, []int) { + return file_yorkie_v1_admin_proto_rawDescGZIP(), []int{31} +} + +func (x *GetServerVersionResponse) GetYorkieVersion() string { + if x != nil { + return x.YorkieVersion + } + return "" +} + +func (x *GetServerVersionResponse) GetGoVersion() string { + if x != nil { + return x.GoVersion + } + return "" +} + +func (x *GetServerVersionResponse) GetBuildDate() string { + if x != nil { + return x.BuildDate + } + return "" +} + var File_yorkie_v1_admin_proto protoreflect.FileDescriptor var file_yorkie_v1_admin_proto_rawDesc = []byte{ @@ -1436,209 +1739,255 @@ var file_yorkie_v1_admin_proto_rawDesc = []byte{ 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x25, 0x0a, 0x0d, 0x4c, 0x6f, 0x67, 0x49, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x2a, 0x0a, 0x14, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x45, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x2c, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x22, - 0x27, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x42, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x50, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x4e, 0x0a, 0x14, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x17, 0x0a, 0x15, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x81, 0x01, 0x0a, 0x15, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x63, + 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x50, 0x61, + 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x6e, 0x65, 0x77, 0x5f, 0x70, 0x61, + 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x65, + 0x77, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x18, 0x0a, 0x16, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x2a, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, + 0x45, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x79, 0x6f, 0x72, 0x6b, + 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x07, 0x70, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x27, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, + 0x42, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x22, 0x15, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x46, 0x0a, 0x14, 0x4c, 0x69, + 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x73, 0x22, 0x61, 0x0a, 0x14, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x39, 0x0a, 0x06, 0x66, 0x69, + 0x65, 0x6c, 0x64, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x79, 0x6f, 0x72, + 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x52, 0x06, 0x66, + 0x69, 0x65, 0x6c, 0x64, 0x73, 0x22, 0x45, 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x15, 0x0a, 0x13, - 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x22, 0x46, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x08, 0x70, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, - 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, - 0x74, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x22, 0x61, 0x0a, 0x14, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x02, 0x69, 0x64, 0x12, 0x39, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, - 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x22, 0x45, - 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x07, 0x70, 0x72, - 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x22, 0xc1, 0x01, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x6f, - 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, - 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x5f, 0x69, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, - 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, - 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x12, 0x29, + 0x65, 0x63, 0x74, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x22, 0xc1, 0x01, 0x0a, + 0x14, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x65, 0x76, + 0x69, 0x6f, 0x75, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, + 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, + 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, + 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x66, 0x6f, 0x72, + 0x77, 0x61, 0x72, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x46, 0x6f, + 0x72, 0x77, 0x61, 0x72, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, + 0x5f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, + 0x22, 0x51, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x09, 0x64, 0x6f, 0x63, + 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x79, + 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, + 0x74, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x09, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x73, 0x22, 0x5a, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, + 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x22, + 0x4d, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x08, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x6d, + 0x6d, 0x61, 0x72, 0x79, 0x52, 0x08, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x88, + 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x64, 0x6f, 0x63, + 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x0c, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, - 0x6f, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, - 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x22, 0x51, 0x0a, 0x15, 0x4c, 0x69, 0x73, - 0x74, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x38, 0x0a, 0x09, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, - 0x79, 0x52, 0x09, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x5a, 0x0a, 0x12, - 0x47, 0x65, 0x74, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, - 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, - 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x6f, 0x63, - 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x22, 0x4d, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x44, - 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x36, 0x0a, 0x08, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x6f, - 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x08, 0x64, - 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x5d, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x44, 0x6f, - 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, - 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, - 0x79, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, - 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x22, 0x50, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x44, 0x6f, 0x63, - 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, - 0x0a, 0x09, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x6f, - 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x09, 0x64, - 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x7a, 0x0a, 0x1c, 0x52, 0x65, 0x6d, 0x6f, - 0x76, 0x65, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x41, 0x64, 0x6d, 0x69, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, - 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x64, - 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0b, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x14, - 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, - 0x6f, 0x72, 0x63, 0x65, 0x22, 0x1f, 0x0a, 0x1d, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x44, 0x6f, - 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x81, 0x01, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x53, 0x6e, 0x61, - 0x70, 0x73, 0x68, 0x6f, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x6f, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, + 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x22, 0x50, 0x0a, 0x14, 0x47, 0x65, 0x74, + 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x38, 0x0a, 0x09, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, + 0x52, 0x09, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x7a, 0x0a, 0x1c, 0x52, + 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x41, + 0x64, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, + 0x0a, 0x0c, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x4b, 0x65, + 0x79, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x22, 0x1f, 0x0a, 0x1d, 0x52, 0x65, 0x6d, 0x6f, 0x76, + 0x65, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x41, 0x64, 0x6d, 0x69, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x81, 0x01, 0x0a, 0x16, 0x47, 0x65, 0x74, + 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x6f, + 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x0a, 0x0a, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x71, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x30, + 0x01, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x65, 0x71, 0x22, 0x94, 0x01, 0x0a, + 0x17, 0x47, 0x65, 0x74, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x4d, 0x65, 0x74, 0x61, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x6e, 0x61, 0x70, + 0x73, 0x68, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x6e, 0x61, 0x70, + 0x73, 0x68, 0x6f, 0x74, 0x12, 0x1c, 0x0a, 0x07, 0x6c, 0x61, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x30, 0x01, 0x52, 0x07, 0x6c, 0x61, 0x6d, 0x70, 0x6f, + 0x72, 0x74, 0x12, 0x3f, 0x0a, 0x0e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x76, 0x65, + 0x63, 0x74, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x79, 0x6f, 0x72, + 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x56, 0x65, + 0x63, 0x74, 0x6f, 0x72, 0x52, 0x0d, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x63, + 0x74, 0x6f, 0x72, 0x22, 0x6e, 0x0a, 0x16, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x6f, 0x63, + 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, + 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, + 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, + 0x69, 0x7a, 0x65, 0x22, 0x74, 0x0a, 0x17, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x6f, 0x63, + 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, + 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0x38, 0x0a, 0x09, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, + 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x09, + 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xbd, 0x01, 0x0a, 0x12, 0x4c, 0x69, + 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x6f, 0x63, 0x75, 0x6d, - 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x5f, 0x73, 0x65, 0x71, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x30, 0x01, 0x52, 0x09, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x65, 0x71, 0x22, 0x94, 0x01, 0x0a, 0x17, 0x47, 0x65, - 0x74, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, - 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, - 0x74, 0x12, 0x1c, 0x0a, 0x07, 0x6c, 0x61, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x03, 0x42, 0x02, 0x30, 0x01, 0x52, 0x07, 0x6c, 0x61, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x12, - 0x3f, 0x0a, 0x0e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x76, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x52, 0x0d, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, - 0x22, 0x6e, 0x0a, 0x16, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, - 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, - 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, - 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, - 0x65, 0x72, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, - 0x22, 0x74, 0x0a, 0x17, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, - 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x74, - 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x38, 0x0a, 0x09, - 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x1a, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x6f, 0x63, 0x75, - 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x09, 0x64, 0x6f, 0x63, - 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xbd, 0x01, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x43, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, - 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, - 0x4b, 0x65, 0x79, 0x12, 0x25, 0x0a, 0x0c, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x5f, - 0x73, 0x65, 0x71, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x30, 0x01, 0x52, 0x0b, 0x70, - 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x53, 0x65, 0x71, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, - 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, - 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x66, 0x6f, - 0x72, 0x77, 0x61, 0x72, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x46, - 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x22, 0x42, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, - 0x07, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, - 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x52, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x32, 0xc8, 0x08, 0x0a, 0x0c, 0x41, - 0x64, 0x6d, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3f, 0x0a, 0x06, 0x53, - 0x69, 0x67, 0x6e, 0x55, 0x70, 0x12, 0x18, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x55, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x19, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, - 0x55, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3c, 0x0a, 0x05, - 0x4c, 0x6f, 0x67, 0x49, 0x6e, 0x12, 0x17, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x49, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, - 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x49, 0x6e, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x54, 0x0a, 0x0d, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1f, 0x2e, 0x79, 0x6f, - 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, - 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x79, - 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, - 0x12, 0x51, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, - 0x12, 0x1e, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1f, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x00, 0x12, 0x4b, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, - 0x74, 0x12, 0x1c, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, - 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1d, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x50, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, - 0x12, 0x54, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, - 0x74, 0x12, 0x1f, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x54, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x6f, - 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1f, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, - 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x0b, - 0x47, 0x65, 0x74, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x2e, 0x79, 0x6f, - 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x6f, 0x63, 0x75, 0x6d, - 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x79, 0x6f, 0x72, + 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x25, 0x0a, 0x0c, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, + 0x75, 0x73, 0x5f, 0x73, 0x65, 0x71, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x30, 0x01, + 0x52, 0x0b, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x53, 0x65, 0x71, 0x12, 0x1b, 0x0a, + 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, + 0x5f, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, + 0x69, 0x73, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x22, 0x42, 0x0a, 0x13, 0x4c, 0x69, 0x73, + 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x2b, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x11, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x52, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x22, 0x19, 0x0a, + 0x17, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x7f, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x5f, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x79, 0x6f, + 0x72, 0x6b, 0x69, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x67, + 0x6f, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x67, 0x6f, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x75, + 0x69, 0x6c, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x62, 0x75, 0x69, 0x6c, 0x64, 0x44, 0x61, 0x74, 0x65, 0x32, 0xd6, 0x0a, 0x0a, 0x0c, 0x41, 0x64, + 0x6d, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3f, 0x0a, 0x06, 0x53, 0x69, + 0x67, 0x6e, 0x55, 0x70, 0x12, 0x18, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x55, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, + 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x55, + 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3c, 0x0a, 0x05, 0x4c, + 0x6f, 0x67, 0x49, 0x6e, 0x12, 0x17, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x4c, 0x6f, 0x67, 0x49, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, + 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x49, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x54, 0x0a, 0x0d, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x2e, 0x79, 0x6f, 0x72, + 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x79, 0x6f, + 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, + 0x57, 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, + 0x64, 0x12, 0x20, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x54, 0x0a, 0x0d, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1f, 0x2e, 0x79, 0x6f, 0x72, 0x6b, + 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x79, 0x6f, 0x72, + 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x51, + 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1e, + 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, + 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x12, 0x4b, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, + 0x1c, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x50, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, + 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x54, + 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, + 0x1f, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x20, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x00, 0x12, 0x54, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x6f, 0x63, 0x75, + 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1f, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x0b, 0x47, 0x65, + 0x74, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x2e, 0x79, 0x6f, 0x72, 0x6b, + 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x0c, 0x47, 0x65, + 0x74, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1e, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, - 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x0c, - 0x47, 0x65, 0x74, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1e, 0x2e, 0x79, - 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x6f, 0x63, 0x75, - 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x79, - 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x6f, 0x63, 0x75, - 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, - 0x6c, 0x0a, 0x15, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, - 0x74, 0x42, 0x79, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x12, 0x27, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x44, 0x6f, 0x63, 0x75, 0x6d, - 0x65, 0x6e, 0x74, 0x42, 0x79, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x28, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, - 0x6d, 0x6f, 0x76, 0x65, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x41, 0x64, - 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5a, 0x0a, - 0x0f, 0x47, 0x65, 0x74, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x4d, 0x65, 0x74, 0x61, - 0x12, 0x21, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, - 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x47, 0x65, 0x74, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5a, 0x0a, 0x0f, 0x53, 0x65, 0x61, - 0x72, 0x63, 0x68, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x21, 0x2e, 0x79, - 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, - 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x22, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x61, 0x72, - 0x63, 0x68, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x73, 0x12, 0x1d, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x45, 0x0a, 0x11, 0x64, 0x65, 0x76, 0x2e, 0x79, 0x6f, 0x72, - 0x6b, 0x69, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x50, 0x01, 0x5a, 0x2e, 0x67, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2d, - 0x74, 0x65, 0x61, 0x6d, 0x2f, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, - 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x79, 0x6f, 0x72, + 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x6c, 0x0a, + 0x15, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x42, + 0x79, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x12, 0x27, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, + 0x74, 0x42, 0x79, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x28, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, + 0x76, 0x65, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x41, 0x64, 0x6d, 0x69, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5a, 0x0a, 0x0f, 0x47, + 0x65, 0x74, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x21, + 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x6e, + 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x22, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, + 0x74, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5a, 0x0a, 0x0f, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x21, 0x2e, 0x79, 0x6f, 0x72, + 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x6f, 0x63, + 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, + 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, + 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x73, 0x12, 0x1d, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1e, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x79, 0x6f, + 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x42, 0x45, 0x0a, 0x11, 0x64, 0x65, 0x76, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x50, 0x01, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2d, 0x74, 0x65, 0x61, + 0x6d, 0x2f, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x79, 0x6f, 0x72, + 0x6b, 0x69, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( @@ -1653,82 +2002,94 @@ func file_yorkie_v1_admin_proto_rawDescGZIP() []byte { return file_yorkie_v1_admin_proto_rawDescData } -var file_yorkie_v1_admin_proto_msgTypes = make([]protoimpl.MessageInfo, 26) +var file_yorkie_v1_admin_proto_msgTypes = make([]protoimpl.MessageInfo, 32) var file_yorkie_v1_admin_proto_goTypes = []interface{}{ (*SignUpRequest)(nil), // 0: yorkie.v1.SignUpRequest (*SignUpResponse)(nil), // 1: yorkie.v1.SignUpResponse (*LogInRequest)(nil), // 2: yorkie.v1.LogInRequest (*LogInResponse)(nil), // 3: yorkie.v1.LogInResponse - (*CreateProjectRequest)(nil), // 4: yorkie.v1.CreateProjectRequest - (*CreateProjectResponse)(nil), // 5: yorkie.v1.CreateProjectResponse - (*GetProjectRequest)(nil), // 6: yorkie.v1.GetProjectRequest - (*GetProjectResponse)(nil), // 7: yorkie.v1.GetProjectResponse - (*ListProjectsRequest)(nil), // 8: yorkie.v1.ListProjectsRequest - (*ListProjectsResponse)(nil), // 9: yorkie.v1.ListProjectsResponse - (*UpdateProjectRequest)(nil), // 10: yorkie.v1.UpdateProjectRequest - (*UpdateProjectResponse)(nil), // 11: yorkie.v1.UpdateProjectResponse - (*ListDocumentsRequest)(nil), // 12: yorkie.v1.ListDocumentsRequest - (*ListDocumentsResponse)(nil), // 13: yorkie.v1.ListDocumentsResponse - (*GetDocumentRequest)(nil), // 14: yorkie.v1.GetDocumentRequest - (*GetDocumentResponse)(nil), // 15: yorkie.v1.GetDocumentResponse - (*GetDocumentsRequest)(nil), // 16: yorkie.v1.GetDocumentsRequest - (*GetDocumentsResponse)(nil), // 17: yorkie.v1.GetDocumentsResponse - (*RemoveDocumentByAdminRequest)(nil), // 18: yorkie.v1.RemoveDocumentByAdminRequest - (*RemoveDocumentByAdminResponse)(nil), // 19: yorkie.v1.RemoveDocumentByAdminResponse - (*GetSnapshotMetaRequest)(nil), // 20: yorkie.v1.GetSnapshotMetaRequest - (*GetSnapshotMetaResponse)(nil), // 21: yorkie.v1.GetSnapshotMetaResponse - (*SearchDocumentsRequest)(nil), // 22: yorkie.v1.SearchDocumentsRequest - (*SearchDocumentsResponse)(nil), // 23: yorkie.v1.SearchDocumentsResponse - (*ListChangesRequest)(nil), // 24: yorkie.v1.ListChangesRequest - (*ListChangesResponse)(nil), // 25: yorkie.v1.ListChangesResponse - (*User)(nil), // 26: yorkie.v1.User - (*Project)(nil), // 27: yorkie.v1.Project - (*UpdatableProjectFields)(nil), // 28: yorkie.v1.UpdatableProjectFields - (*DocumentSummary)(nil), // 29: yorkie.v1.DocumentSummary - (*VersionVector)(nil), // 30: yorkie.v1.VersionVector - (*Change)(nil), // 31: yorkie.v1.Change + (*DeleteAccountRequest)(nil), // 4: yorkie.v1.DeleteAccountRequest + (*DeleteAccountResponse)(nil), // 5: yorkie.v1.DeleteAccountResponse + (*ChangePasswordRequest)(nil), // 6: yorkie.v1.ChangePasswordRequest + (*ChangePasswordResponse)(nil), // 7: yorkie.v1.ChangePasswordResponse + (*CreateProjectRequest)(nil), // 8: yorkie.v1.CreateProjectRequest + (*CreateProjectResponse)(nil), // 9: yorkie.v1.CreateProjectResponse + (*GetProjectRequest)(nil), // 10: yorkie.v1.GetProjectRequest + (*GetProjectResponse)(nil), // 11: yorkie.v1.GetProjectResponse + (*ListProjectsRequest)(nil), // 12: yorkie.v1.ListProjectsRequest + (*ListProjectsResponse)(nil), // 13: yorkie.v1.ListProjectsResponse + (*UpdateProjectRequest)(nil), // 14: yorkie.v1.UpdateProjectRequest + (*UpdateProjectResponse)(nil), // 15: yorkie.v1.UpdateProjectResponse + (*ListDocumentsRequest)(nil), // 16: yorkie.v1.ListDocumentsRequest + (*ListDocumentsResponse)(nil), // 17: yorkie.v1.ListDocumentsResponse + (*GetDocumentRequest)(nil), // 18: yorkie.v1.GetDocumentRequest + (*GetDocumentResponse)(nil), // 19: yorkie.v1.GetDocumentResponse + (*GetDocumentsRequest)(nil), // 20: yorkie.v1.GetDocumentsRequest + (*GetDocumentsResponse)(nil), // 21: yorkie.v1.GetDocumentsResponse + (*RemoveDocumentByAdminRequest)(nil), // 22: yorkie.v1.RemoveDocumentByAdminRequest + (*RemoveDocumentByAdminResponse)(nil), // 23: yorkie.v1.RemoveDocumentByAdminResponse + (*GetSnapshotMetaRequest)(nil), // 24: yorkie.v1.GetSnapshotMetaRequest + (*GetSnapshotMetaResponse)(nil), // 25: yorkie.v1.GetSnapshotMetaResponse + (*SearchDocumentsRequest)(nil), // 26: yorkie.v1.SearchDocumentsRequest + (*SearchDocumentsResponse)(nil), // 27: yorkie.v1.SearchDocumentsResponse + (*ListChangesRequest)(nil), // 28: yorkie.v1.ListChangesRequest + (*ListChangesResponse)(nil), // 29: yorkie.v1.ListChangesResponse + (*GetServerVersionRequest)(nil), // 30: yorkie.v1.GetServerVersionRequest + (*GetServerVersionResponse)(nil), // 31: yorkie.v1.GetServerVersionResponse + (*User)(nil), // 32: yorkie.v1.User + (*Project)(nil), // 33: yorkie.v1.Project + (*UpdatableProjectFields)(nil), // 34: yorkie.v1.UpdatableProjectFields + (*DocumentSummary)(nil), // 35: yorkie.v1.DocumentSummary + (*VersionVector)(nil), // 36: yorkie.v1.VersionVector + (*Change)(nil), // 37: yorkie.v1.Change } var file_yorkie_v1_admin_proto_depIdxs = []int32{ - 26, // 0: yorkie.v1.SignUpResponse.user:type_name -> yorkie.v1.User - 27, // 1: yorkie.v1.CreateProjectResponse.project:type_name -> yorkie.v1.Project - 27, // 2: yorkie.v1.GetProjectResponse.project:type_name -> yorkie.v1.Project - 27, // 3: yorkie.v1.ListProjectsResponse.projects:type_name -> yorkie.v1.Project - 28, // 4: yorkie.v1.UpdateProjectRequest.fields:type_name -> yorkie.v1.UpdatableProjectFields - 27, // 5: yorkie.v1.UpdateProjectResponse.project:type_name -> yorkie.v1.Project - 29, // 6: yorkie.v1.ListDocumentsResponse.documents:type_name -> yorkie.v1.DocumentSummary - 29, // 7: yorkie.v1.GetDocumentResponse.document:type_name -> yorkie.v1.DocumentSummary - 29, // 8: yorkie.v1.GetDocumentsResponse.documents:type_name -> yorkie.v1.DocumentSummary - 30, // 9: yorkie.v1.GetSnapshotMetaResponse.version_vector:type_name -> yorkie.v1.VersionVector - 29, // 10: yorkie.v1.SearchDocumentsResponse.documents:type_name -> yorkie.v1.DocumentSummary - 31, // 11: yorkie.v1.ListChangesResponse.changes:type_name -> yorkie.v1.Change + 32, // 0: yorkie.v1.SignUpResponse.user:type_name -> yorkie.v1.User + 33, // 1: yorkie.v1.CreateProjectResponse.project:type_name -> yorkie.v1.Project + 33, // 2: yorkie.v1.GetProjectResponse.project:type_name -> yorkie.v1.Project + 33, // 3: yorkie.v1.ListProjectsResponse.projects:type_name -> yorkie.v1.Project + 34, // 4: yorkie.v1.UpdateProjectRequest.fields:type_name -> yorkie.v1.UpdatableProjectFields + 33, // 5: yorkie.v1.UpdateProjectResponse.project:type_name -> yorkie.v1.Project + 35, // 6: yorkie.v1.ListDocumentsResponse.documents:type_name -> yorkie.v1.DocumentSummary + 35, // 7: yorkie.v1.GetDocumentResponse.document:type_name -> yorkie.v1.DocumentSummary + 35, // 8: yorkie.v1.GetDocumentsResponse.documents:type_name -> yorkie.v1.DocumentSummary + 36, // 9: yorkie.v1.GetSnapshotMetaResponse.version_vector:type_name -> yorkie.v1.VersionVector + 35, // 10: yorkie.v1.SearchDocumentsResponse.documents:type_name -> yorkie.v1.DocumentSummary + 37, // 11: yorkie.v1.ListChangesResponse.changes:type_name -> yorkie.v1.Change 0, // 12: yorkie.v1.AdminService.SignUp:input_type -> yorkie.v1.SignUpRequest 2, // 13: yorkie.v1.AdminService.LogIn:input_type -> yorkie.v1.LogInRequest - 4, // 14: yorkie.v1.AdminService.CreateProject:input_type -> yorkie.v1.CreateProjectRequest - 8, // 15: yorkie.v1.AdminService.ListProjects:input_type -> yorkie.v1.ListProjectsRequest - 6, // 16: yorkie.v1.AdminService.GetProject:input_type -> yorkie.v1.GetProjectRequest - 10, // 17: yorkie.v1.AdminService.UpdateProject:input_type -> yorkie.v1.UpdateProjectRequest - 12, // 18: yorkie.v1.AdminService.ListDocuments:input_type -> yorkie.v1.ListDocumentsRequest - 14, // 19: yorkie.v1.AdminService.GetDocument:input_type -> yorkie.v1.GetDocumentRequest - 16, // 20: yorkie.v1.AdminService.GetDocuments:input_type -> yorkie.v1.GetDocumentsRequest - 18, // 21: yorkie.v1.AdminService.RemoveDocumentByAdmin:input_type -> yorkie.v1.RemoveDocumentByAdminRequest - 20, // 22: yorkie.v1.AdminService.GetSnapshotMeta:input_type -> yorkie.v1.GetSnapshotMetaRequest - 22, // 23: yorkie.v1.AdminService.SearchDocuments:input_type -> yorkie.v1.SearchDocumentsRequest - 24, // 24: yorkie.v1.AdminService.ListChanges:input_type -> yorkie.v1.ListChangesRequest - 1, // 25: yorkie.v1.AdminService.SignUp:output_type -> yorkie.v1.SignUpResponse - 3, // 26: yorkie.v1.AdminService.LogIn:output_type -> yorkie.v1.LogInResponse - 5, // 27: yorkie.v1.AdminService.CreateProject:output_type -> yorkie.v1.CreateProjectResponse - 9, // 28: yorkie.v1.AdminService.ListProjects:output_type -> yorkie.v1.ListProjectsResponse - 7, // 29: yorkie.v1.AdminService.GetProject:output_type -> yorkie.v1.GetProjectResponse - 11, // 30: yorkie.v1.AdminService.UpdateProject:output_type -> yorkie.v1.UpdateProjectResponse - 13, // 31: yorkie.v1.AdminService.ListDocuments:output_type -> yorkie.v1.ListDocumentsResponse - 15, // 32: yorkie.v1.AdminService.GetDocument:output_type -> yorkie.v1.GetDocumentResponse - 17, // 33: yorkie.v1.AdminService.GetDocuments:output_type -> yorkie.v1.GetDocumentsResponse - 19, // 34: yorkie.v1.AdminService.RemoveDocumentByAdmin:output_type -> yorkie.v1.RemoveDocumentByAdminResponse - 21, // 35: yorkie.v1.AdminService.GetSnapshotMeta:output_type -> yorkie.v1.GetSnapshotMetaResponse - 23, // 36: yorkie.v1.AdminService.SearchDocuments:output_type -> yorkie.v1.SearchDocumentsResponse - 25, // 37: yorkie.v1.AdminService.ListChanges:output_type -> yorkie.v1.ListChangesResponse - 25, // [25:38] is the sub-list for method output_type - 12, // [12:25] is the sub-list for method input_type + 4, // 14: yorkie.v1.AdminService.DeleteAccount:input_type -> yorkie.v1.DeleteAccountRequest + 6, // 15: yorkie.v1.AdminService.ChangePassword:input_type -> yorkie.v1.ChangePasswordRequest + 8, // 16: yorkie.v1.AdminService.CreateProject:input_type -> yorkie.v1.CreateProjectRequest + 12, // 17: yorkie.v1.AdminService.ListProjects:input_type -> yorkie.v1.ListProjectsRequest + 10, // 18: yorkie.v1.AdminService.GetProject:input_type -> yorkie.v1.GetProjectRequest + 14, // 19: yorkie.v1.AdminService.UpdateProject:input_type -> yorkie.v1.UpdateProjectRequest + 16, // 20: yorkie.v1.AdminService.ListDocuments:input_type -> yorkie.v1.ListDocumentsRequest + 18, // 21: yorkie.v1.AdminService.GetDocument:input_type -> yorkie.v1.GetDocumentRequest + 20, // 22: yorkie.v1.AdminService.GetDocuments:input_type -> yorkie.v1.GetDocumentsRequest + 22, // 23: yorkie.v1.AdminService.RemoveDocumentByAdmin:input_type -> yorkie.v1.RemoveDocumentByAdminRequest + 24, // 24: yorkie.v1.AdminService.GetSnapshotMeta:input_type -> yorkie.v1.GetSnapshotMetaRequest + 26, // 25: yorkie.v1.AdminService.SearchDocuments:input_type -> yorkie.v1.SearchDocumentsRequest + 28, // 26: yorkie.v1.AdminService.ListChanges:input_type -> yorkie.v1.ListChangesRequest + 30, // 27: yorkie.v1.AdminService.GetServerVersion:input_type -> yorkie.v1.GetServerVersionRequest + 1, // 28: yorkie.v1.AdminService.SignUp:output_type -> yorkie.v1.SignUpResponse + 3, // 29: yorkie.v1.AdminService.LogIn:output_type -> yorkie.v1.LogInResponse + 5, // 30: yorkie.v1.AdminService.DeleteAccount:output_type -> yorkie.v1.DeleteAccountResponse + 7, // 31: yorkie.v1.AdminService.ChangePassword:output_type -> yorkie.v1.ChangePasswordResponse + 9, // 32: yorkie.v1.AdminService.CreateProject:output_type -> yorkie.v1.CreateProjectResponse + 13, // 33: yorkie.v1.AdminService.ListProjects:output_type -> yorkie.v1.ListProjectsResponse + 11, // 34: yorkie.v1.AdminService.GetProject:output_type -> yorkie.v1.GetProjectResponse + 15, // 35: yorkie.v1.AdminService.UpdateProject:output_type -> yorkie.v1.UpdateProjectResponse + 17, // 36: yorkie.v1.AdminService.ListDocuments:output_type -> yorkie.v1.ListDocumentsResponse + 19, // 37: yorkie.v1.AdminService.GetDocument:output_type -> yorkie.v1.GetDocumentResponse + 21, // 38: yorkie.v1.AdminService.GetDocuments:output_type -> yorkie.v1.GetDocumentsResponse + 23, // 39: yorkie.v1.AdminService.RemoveDocumentByAdmin:output_type -> yorkie.v1.RemoveDocumentByAdminResponse + 25, // 40: yorkie.v1.AdminService.GetSnapshotMeta:output_type -> yorkie.v1.GetSnapshotMetaResponse + 27, // 41: yorkie.v1.AdminService.SearchDocuments:output_type -> yorkie.v1.SearchDocumentsResponse + 29, // 42: yorkie.v1.AdminService.ListChanges:output_type -> yorkie.v1.ListChangesResponse + 31, // 43: yorkie.v1.AdminService.GetServerVersion:output_type -> yorkie.v1.GetServerVersionResponse + 28, // [28:44] is the sub-list for method output_type + 12, // [12:28] is the sub-list for method input_type 12, // [12:12] is the sub-list for extension type_name 12, // [12:12] is the sub-list for extension extendee 0, // [0:12] is the sub-list for field type_name @@ -1790,7 +2151,7 @@ func file_yorkie_v1_admin_proto_init() { } } file_yorkie_v1_admin_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateProjectRequest); i { + switch v := v.(*DeleteAccountRequest); i { case 0: return &v.state case 1: @@ -1802,7 +2163,7 @@ func file_yorkie_v1_admin_proto_init() { } } file_yorkie_v1_admin_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateProjectResponse); i { + switch v := v.(*DeleteAccountResponse); i { case 0: return &v.state case 1: @@ -1814,7 +2175,7 @@ func file_yorkie_v1_admin_proto_init() { } } file_yorkie_v1_admin_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetProjectRequest); i { + switch v := v.(*ChangePasswordRequest); i { case 0: return &v.state case 1: @@ -1826,7 +2187,7 @@ func file_yorkie_v1_admin_proto_init() { } } file_yorkie_v1_admin_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetProjectResponse); i { + switch v := v.(*ChangePasswordResponse); i { case 0: return &v.state case 1: @@ -1838,7 +2199,7 @@ func file_yorkie_v1_admin_proto_init() { } } file_yorkie_v1_admin_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListProjectsRequest); i { + switch v := v.(*CreateProjectRequest); i { case 0: return &v.state case 1: @@ -1850,7 +2211,7 @@ func file_yorkie_v1_admin_proto_init() { } } file_yorkie_v1_admin_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListProjectsResponse); i { + switch v := v.(*CreateProjectResponse); i { case 0: return &v.state case 1: @@ -1862,7 +2223,7 @@ func file_yorkie_v1_admin_proto_init() { } } file_yorkie_v1_admin_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdateProjectRequest); i { + switch v := v.(*GetProjectRequest); i { case 0: return &v.state case 1: @@ -1874,7 +2235,7 @@ func file_yorkie_v1_admin_proto_init() { } } file_yorkie_v1_admin_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdateProjectResponse); i { + switch v := v.(*GetProjectResponse); i { case 0: return &v.state case 1: @@ -1886,7 +2247,7 @@ func file_yorkie_v1_admin_proto_init() { } } file_yorkie_v1_admin_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListDocumentsRequest); i { + switch v := v.(*ListProjectsRequest); i { case 0: return &v.state case 1: @@ -1898,7 +2259,7 @@ func file_yorkie_v1_admin_proto_init() { } } file_yorkie_v1_admin_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListDocumentsResponse); i { + switch v := v.(*ListProjectsResponse); i { case 0: return &v.state case 1: @@ -1910,7 +2271,7 @@ func file_yorkie_v1_admin_proto_init() { } } file_yorkie_v1_admin_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetDocumentRequest); i { + switch v := v.(*UpdateProjectRequest); i { case 0: return &v.state case 1: @@ -1922,7 +2283,7 @@ func file_yorkie_v1_admin_proto_init() { } } file_yorkie_v1_admin_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetDocumentResponse); i { + switch v := v.(*UpdateProjectResponse); i { case 0: return &v.state case 1: @@ -1934,7 +2295,7 @@ func file_yorkie_v1_admin_proto_init() { } } file_yorkie_v1_admin_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetDocumentsRequest); i { + switch v := v.(*ListDocumentsRequest); i { case 0: return &v.state case 1: @@ -1946,7 +2307,7 @@ func file_yorkie_v1_admin_proto_init() { } } file_yorkie_v1_admin_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetDocumentsResponse); i { + switch v := v.(*ListDocumentsResponse); i { case 0: return &v.state case 1: @@ -1958,7 +2319,7 @@ func file_yorkie_v1_admin_proto_init() { } } file_yorkie_v1_admin_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RemoveDocumentByAdminRequest); i { + switch v := v.(*GetDocumentRequest); i { case 0: return &v.state case 1: @@ -1970,7 +2331,7 @@ func file_yorkie_v1_admin_proto_init() { } } file_yorkie_v1_admin_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RemoveDocumentByAdminResponse); i { + switch v := v.(*GetDocumentResponse); i { case 0: return &v.state case 1: @@ -1982,7 +2343,7 @@ func file_yorkie_v1_admin_proto_init() { } } file_yorkie_v1_admin_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSnapshotMetaRequest); i { + switch v := v.(*GetDocumentsRequest); i { case 0: return &v.state case 1: @@ -1994,7 +2355,7 @@ func file_yorkie_v1_admin_proto_init() { } } file_yorkie_v1_admin_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSnapshotMetaResponse); i { + switch v := v.(*GetDocumentsResponse); i { case 0: return &v.state case 1: @@ -2006,7 +2367,7 @@ func file_yorkie_v1_admin_proto_init() { } } file_yorkie_v1_admin_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SearchDocumentsRequest); i { + switch v := v.(*RemoveDocumentByAdminRequest); i { case 0: return &v.state case 1: @@ -2018,7 +2379,7 @@ func file_yorkie_v1_admin_proto_init() { } } file_yorkie_v1_admin_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SearchDocumentsResponse); i { + switch v := v.(*RemoveDocumentByAdminResponse); i { case 0: return &v.state case 1: @@ -2030,7 +2391,7 @@ func file_yorkie_v1_admin_proto_init() { } } file_yorkie_v1_admin_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListChangesRequest); i { + switch v := v.(*GetSnapshotMetaRequest); i { case 0: return &v.state case 1: @@ -2042,6 +2403,54 @@ func file_yorkie_v1_admin_proto_init() { } } file_yorkie_v1_admin_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSnapshotMetaResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_yorkie_v1_admin_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchDocumentsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_yorkie_v1_admin_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchDocumentsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_yorkie_v1_admin_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListChangesRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_yorkie_v1_admin_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ListChangesResponse); i { case 0: return &v.state @@ -2053,6 +2462,30 @@ func file_yorkie_v1_admin_proto_init() { return nil } } + file_yorkie_v1_admin_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetServerVersionRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_yorkie_v1_admin_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetServerVersionResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -2060,7 +2493,7 @@ func file_yorkie_v1_admin_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_yorkie_v1_admin_proto_rawDesc, NumEnums: 0, - NumMessages: 26, + NumMessages: 32, NumExtensions: 0, NumServices: 1, }, diff --git a/api/yorkie/v1/admin.proto b/api/yorkie/v1/admin.proto index 6eeaac248..6fd3c7308 100644 --- a/api/yorkie/v1/admin.proto +++ b/api/yorkie/v1/admin.proto @@ -28,6 +28,8 @@ option java_package = "dev.yorkie.api.v1"; service AdminService { rpc SignUp(SignUpRequest) returns (SignUpResponse) {} rpc LogIn(LogInRequest) returns (LogInResponse) {} + rpc DeleteAccount(DeleteAccountRequest) returns (DeleteAccountResponse) {} + rpc ChangePassword(ChangePasswordRequest) returns (ChangePasswordResponse) {} rpc CreateProject(CreateProjectRequest) returns (CreateProjectResponse) {} rpc ListProjects(ListProjectsRequest) returns (ListProjectsResponse) {} @@ -42,6 +44,8 @@ service AdminService { rpc SearchDocuments (SearchDocumentsRequest) returns (SearchDocumentsResponse) {} rpc ListChanges (ListChangesRequest) returns (ListChangesResponse) {} + + rpc GetServerVersion (GetServerVersionRequest) returns (GetServerVersionResponse) {} } message SignUpRequest { @@ -62,6 +66,23 @@ message LogInResponse { string token = 1; } +message DeleteAccountRequest { + string username = 1; + string password = 2; +} + +message DeleteAccountResponse { +} + +message ChangePasswordRequest { + string username = 1; + string current_password = 2; + string new_password = 3; +} + +message ChangePasswordResponse { +} + message CreateProjectRequest { string name = 1; } @@ -117,6 +138,7 @@ message GetDocumentResponse { message GetDocumentsRequest { string project_name = 1; repeated string document_keys = 2; + bool include_snapshot = 3; } message GetDocumentsResponse { @@ -165,3 +187,11 @@ message ListChangesRequest { message ListChangesResponse { repeated Change changes = 1; } + +message GetServerVersionRequest {} + +message GetServerVersionResponse { + string yorkie_version = 1; + string go_version = 2; + string build_date = 3; +} diff --git a/api/yorkie/v1/resources.pb.go b/api/yorkie/v1/resources.pb.go index 8c2015e27..6f0c7130a 100644 --- a/api/yorkie/v1/resources.pb.go +++ b/api/yorkie/v1/resources.pb.go @@ -608,6 +608,7 @@ type Operation struct { // *Operation_Increase_ // *Operation_TreeEdit_ // *Operation_TreeStyle_ + // *Operation_ArraySet_ Body isOperation_Body `protobuf_oneof:"body"` } @@ -720,6 +721,13 @@ func (x *Operation) GetTreeStyle() *Operation_TreeStyle { return nil } +func (x *Operation) GetArraySet() *Operation_ArraySet { + if x, ok := x.GetBody().(*Operation_ArraySet_); ok { + return x.ArraySet + } + return nil +} + type isOperation_Body interface { isOperation_Body() } @@ -764,6 +772,10 @@ type Operation_TreeStyle_ struct { TreeStyle *Operation_TreeStyle `protobuf:"bytes,10,opt,name=tree_style,json=treeStyle,proto3,oneof"` } +type Operation_ArraySet_ struct { + ArraySet *Operation_ArraySet `protobuf:"bytes,11,opt,name=array_set,json=arraySet,proto3,oneof"` +} + func (*Operation_Set_) isOperation_Body() {} func (*Operation_Add_) isOperation_Body() {} @@ -784,6 +796,8 @@ func (*Operation_TreeEdit_) isOperation_Body() {} func (*Operation_TreeStyle_) isOperation_Body() {} +func (*Operation_ArraySet_) isOperation_Body() {} + type JSONElementSimple struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -3086,6 +3100,77 @@ func (x *Operation_TreeStyle) GetCreatedAtMapByActor() map[string]*TimeTicket { return nil } +type Operation_ArraySet struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ParentCreatedAt *TimeTicket `protobuf:"bytes,1,opt,name=parent_created_at,json=parentCreatedAt,proto3" json:"parent_created_at,omitempty"` + CreatedAt *TimeTicket `protobuf:"bytes,2,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + Value *JSONElementSimple `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` + ExecutedAt *TimeTicket `protobuf:"bytes,4,opt,name=executed_at,json=executedAt,proto3" json:"executed_at,omitempty"` +} + +func (x *Operation_ArraySet) Reset() { + *x = Operation_ArraySet{} + if protoimpl.UnsafeEnabled { + mi := &file_yorkie_v1_resources_proto_msgTypes[40] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Operation_ArraySet) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Operation_ArraySet) ProtoMessage() {} + +func (x *Operation_ArraySet) ProtoReflect() protoreflect.Message { + mi := &file_yorkie_v1_resources_proto_msgTypes[40] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Operation_ArraySet.ProtoReflect.Descriptor instead. +func (*Operation_ArraySet) Descriptor() ([]byte, []int) { + return file_yorkie_v1_resources_proto_rawDescGZIP(), []int{5, 10} +} + +func (x *Operation_ArraySet) GetParentCreatedAt() *TimeTicket { + if x != nil { + return x.ParentCreatedAt + } + return nil +} + +func (x *Operation_ArraySet) GetCreatedAt() *TimeTicket { + if x != nil { + return x.CreatedAt + } + return nil +} + +func (x *Operation_ArraySet) GetValue() *JSONElementSimple { + if x != nil { + return x.Value + } + return nil +} + +func (x *Operation_ArraySet) GetExecutedAt() *TimeTicket { + if x != nil { + return x.ExecutedAt + } + return nil +} + type JSONElement_JSONObject struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -3100,7 +3185,7 @@ type JSONElement_JSONObject struct { func (x *JSONElement_JSONObject) Reset() { *x = JSONElement_JSONObject{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_resources_proto_msgTypes[47] + mi := &file_yorkie_v1_resources_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3113,7 +3198,7 @@ func (x *JSONElement_JSONObject) String() string { func (*JSONElement_JSONObject) ProtoMessage() {} func (x *JSONElement_JSONObject) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_resources_proto_msgTypes[47] + mi := &file_yorkie_v1_resources_proto_msgTypes[48] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3171,7 +3256,7 @@ type JSONElement_JSONArray struct { func (x *JSONElement_JSONArray) Reset() { *x = JSONElement_JSONArray{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_resources_proto_msgTypes[48] + mi := &file_yorkie_v1_resources_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3184,7 +3269,7 @@ func (x *JSONElement_JSONArray) String() string { func (*JSONElement_JSONArray) ProtoMessage() {} func (x *JSONElement_JSONArray) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_resources_proto_msgTypes[48] + mi := &file_yorkie_v1_resources_proto_msgTypes[49] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3243,7 +3328,7 @@ type JSONElement_Primitive struct { func (x *JSONElement_Primitive) Reset() { *x = JSONElement_Primitive{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_resources_proto_msgTypes[49] + mi := &file_yorkie_v1_resources_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3256,7 +3341,7 @@ func (x *JSONElement_Primitive) String() string { func (*JSONElement_Primitive) ProtoMessage() {} func (x *JSONElement_Primitive) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_resources_proto_msgTypes[49] + mi := &file_yorkie_v1_resources_proto_msgTypes[50] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3321,7 +3406,7 @@ type JSONElement_Text struct { func (x *JSONElement_Text) Reset() { *x = JSONElement_Text{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_resources_proto_msgTypes[50] + mi := &file_yorkie_v1_resources_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3334,7 +3419,7 @@ func (x *JSONElement_Text) String() string { func (*JSONElement_Text) ProtoMessage() {} func (x *JSONElement_Text) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_resources_proto_msgTypes[50] + mi := &file_yorkie_v1_resources_proto_msgTypes[51] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3393,7 +3478,7 @@ type JSONElement_Counter struct { func (x *JSONElement_Counter) Reset() { *x = JSONElement_Counter{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_resources_proto_msgTypes[51] + mi := &file_yorkie_v1_resources_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3406,7 +3491,7 @@ func (x *JSONElement_Counter) String() string { func (*JSONElement_Counter) ProtoMessage() {} func (x *JSONElement_Counter) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_resources_proto_msgTypes[51] + mi := &file_yorkie_v1_resources_proto_msgTypes[52] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3471,7 +3556,7 @@ type JSONElement_Tree struct { func (x *JSONElement_Tree) Reset() { *x = JSONElement_Tree{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_resources_proto_msgTypes[52] + mi := &file_yorkie_v1_resources_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3484,7 +3569,7 @@ func (x *JSONElement_Tree) String() string { func (*JSONElement_Tree) ProtoMessage() {} func (x *JSONElement_Tree) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_resources_proto_msgTypes[52] + mi := &file_yorkie_v1_resources_proto_msgTypes[53] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3539,7 +3624,7 @@ type UpdatableProjectFields_AuthWebhookMethods struct { func (x *UpdatableProjectFields_AuthWebhookMethods) Reset() { *x = UpdatableProjectFields_AuthWebhookMethods{} if protoimpl.UnsafeEnabled { - mi := &file_yorkie_v1_resources_proto_msgTypes[55] + mi := &file_yorkie_v1_resources_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3552,7 +3637,7 @@ func (x *UpdatableProjectFields_AuthWebhookMethods) String() string { func (*UpdatableProjectFields_AuthWebhookMethods) ProtoMessage() {} func (x *UpdatableProjectFields_AuthWebhookMethods) ProtoReflect() protoreflect.Message { - mi := &file_yorkie_v1_resources_proto_msgTypes[55] + mi := &file_yorkie_v1_resources_proto_msgTypes[56] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3662,7 +3747,7 @@ var file_yorkie_v1_resources_proto_rawDesc = []byte{ 0x0a, 0x0b, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x84, 0x20, 0x0a, 0x09, 0x4f, 0x70, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xb4, 0x22, 0x0a, 0x09, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x03, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x74, 0x48, 0x00, @@ -3697,228 +3782,247 @@ var file_yorkie_v1_resources_proto_rawDesc = []byte{ 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x48, 0x00, 0x52, 0x09, 0x74, 0x72, 0x65, 0x65, 0x53, 0x74, - 0x79, 0x6c, 0x65, 0x1a, 0xc6, 0x01, 0x0a, 0x03, 0x53, 0x65, 0x74, 0x12, 0x41, 0x0a, 0x11, 0x70, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0f, 0x70, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x10, - 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, - 0x12, 0x32, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1c, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, - 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x12, 0x36, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, - 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, - 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, - 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, 0x74, 0x1a, 0xf3, 0x01, 0x0a, - 0x03, 0x41, 0x64, 0x64, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, + 0x79, 0x6c, 0x65, 0x12, 0x3c, 0x0a, 0x09, 0x61, 0x72, 0x72, 0x61, 0x79, 0x5f, 0x73, 0x65, 0x74, + 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x41, 0x72, 0x72, + 0x61, 0x79, 0x53, 0x65, 0x74, 0x48, 0x00, 0x52, 0x08, 0x61, 0x72, 0x72, 0x61, 0x79, 0x53, 0x65, + 0x74, 0x1a, 0xc6, 0x01, 0x0a, 0x03, 0x53, 0x65, 0x74, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x61, 0x72, + 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0f, 0x70, 0x61, 0x72, + 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x10, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x32, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x45, 0x6c, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x12, 0x36, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, + 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, + 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, 0x74, 0x1a, 0xf3, 0x01, 0x0a, 0x03, 0x41, + 0x64, 0x64, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, + 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, + 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x3d, 0x0a, 0x0f, 0x70, 0x72, 0x65, 0x76, 0x5f, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, + 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, + 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0d, 0x70, 0x72, 0x65, 0x76, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x64, 0x41, 0x74, 0x12, 0x32, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x4a, 0x53, 0x4f, 0x4e, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x69, 0x6d, 0x70, 0x6c, + 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x36, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, + 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, + 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, + 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, 0x74, + 0x1a, 0xf6, 0x01, 0x0a, 0x04, 0x4d, 0x6f, 0x76, 0x65, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x61, 0x72, + 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0f, 0x70, 0x61, 0x72, + 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x3d, 0x0a, 0x0f, + 0x70, 0x72, 0x65, 0x76, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0d, 0x70, 0x72, + 0x65, 0x76, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x34, 0x0a, 0x0a, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, + 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, + 0x74, 0x12, 0x36, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, + 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, 0x74, 0x1a, 0xb9, 0x01, 0x0a, 0x06, 0x52, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x3d, 0x0a, 0x0f, 0x70, 0x72, 0x65, 0x76, 0x5f, - 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x34, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, + 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, + 0x65, 0x74, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x36, 0x0a, + 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, + 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, + 0x74, 0x65, 0x64, 0x41, 0x74, 0x1a, 0xc2, 0x04, 0x0a, 0x04, 0x45, 0x64, 0x69, 0x74, 0x12, 0x41, + 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, + 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, + 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, + 0x74, 0x12, 0x2a, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x16, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x78, 0x74, + 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x73, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x26, 0x0a, + 0x02, 0x74, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x79, 0x6f, 0x72, 0x6b, + 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x78, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, + 0x73, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x68, 0x0a, 0x17, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x61, 0x70, 0x5f, 0x62, 0x79, 0x5f, 0x61, 0x63, 0x74, 0x6f, 0x72, + 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x45, 0x64, 0x69, + 0x74, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, 0x79, + 0x41, 0x63, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x13, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x12, + 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x36, 0x0a, 0x0b, 0x65, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, + 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, + 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, + 0x74, 0x12, 0x49, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, + 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x45, 0x64, 0x69, 0x74, + 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x1a, 0x5d, 0x0a, 0x18, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, + 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2b, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, + 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, + 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0xd7, 0x01, 0x0a, 0x06, 0x53, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, - 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0d, 0x70, 0x72, 0x65, 0x76, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x32, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x69, 0x6d, - 0x70, 0x6c, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x36, 0x0a, 0x0b, 0x65, 0x78, - 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, - 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, - 0x41, 0x74, 0x1a, 0xf6, 0x01, 0x0a, 0x04, 0x4d, 0x6f, 0x76, 0x65, 0x12, 0x41, 0x0a, 0x11, 0x70, + 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x2a, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x54, 0x65, 0x78, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x73, 0x52, 0x04, + 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x26, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x16, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x78, + 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x73, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x36, 0x0a, 0x0b, + 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, + 0x65, 0x64, 0x41, 0x74, 0x1a, 0xab, 0x04, 0x0a, 0x05, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x12, 0x41, + 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, + 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, + 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, + 0x74, 0x12, 0x2a, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x16, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x78, 0x74, + 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x73, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x26, 0x0a, + 0x02, 0x74, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x79, 0x6f, 0x72, 0x6b, + 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x78, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, + 0x73, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x4a, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, + 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x79, 0x6f, 0x72, 0x6b, + 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x53, 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, + 0x73, 0x12, 0x36, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, + 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x69, 0x0a, 0x17, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x61, 0x70, 0x5f, 0x62, 0x79, 0x5f, 0x61, + 0x63, 0x74, 0x6f, 0x72, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x79, 0x6f, 0x72, + 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, + 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x13, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, + 0x63, 0x74, 0x6f, 0x72, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x1a, 0x5d, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, + 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x2b, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, + 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x1a, 0xb9, 0x01, 0x0a, 0x08, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x61, 0x73, 0x65, 0x12, + 0x41, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, + 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, + 0x74, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x41, 0x74, 0x12, 0x32, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1c, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x53, + 0x4f, 0x4e, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x36, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, + 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, + 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, + 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, 0x74, 0x1a, 0xf1, + 0x03, 0x0a, 0x08, 0x54, 0x72, 0x65, 0x65, 0x45, 0x64, 0x69, 0x74, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0f, 0x70, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x3d, - 0x0a, 0x0f, 0x70, 0x72, 0x65, 0x76, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0d, - 0x70, 0x72, 0x65, 0x76, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x34, 0x0a, - 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, - 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x64, 0x41, 0x74, 0x12, 0x36, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, - 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, - 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, 0x74, 0x1a, 0xb9, 0x01, 0x0a, 0x06, - 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, - 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x34, 0x0a, 0x0a, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, - 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, - 0x63, 0x6b, 0x65, 0x74, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, - 0x36, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, - 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, 0x74, 0x1a, 0xc2, 0x04, 0x0a, 0x04, 0x45, 0x64, 0x69, 0x74, - 0x12, 0x41, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, - 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, - 0x65, 0x74, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x64, 0x41, 0x74, 0x12, 0x2a, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x16, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, - 0x78, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x73, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, - 0x26, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x79, 0x6f, - 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x78, 0x74, 0x4e, 0x6f, 0x64, 0x65, - 0x50, 0x6f, 0x73, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x68, 0x0a, 0x17, 0x63, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x61, 0x70, 0x5f, 0x62, 0x79, 0x5f, 0x61, 0x63, 0x74, - 0x6f, 0x72, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x45, - 0x64, 0x69, 0x74, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, 0x70, - 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x13, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, - 0x72, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x36, 0x0a, 0x0b, 0x65, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x26, + 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x79, + 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x50, 0x6f, 0x73, + 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x22, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, + 0x72, 0x65, 0x65, 0x50, 0x6f, 0x73, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x6c, 0x0a, 0x17, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x61, 0x70, 0x5f, 0x62, 0x79, 0x5f, + 0x61, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x79, 0x6f, + 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x45, 0x64, 0x69, 0x74, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x13, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, + 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x30, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x79, 0x6f, 0x72, + 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x73, + 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x70, + 0x6c, 0x69, 0x74, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x0a, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x36, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, - 0x64, 0x41, 0x74, 0x12, 0x49, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, - 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x45, 0x64, - 0x69, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x1a, 0x5d, - 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, 0x79, - 0x41, 0x63, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, - 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2b, 0x0a, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, - 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, - 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, 0x0a, - 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0xd7, 0x01, 0x0a, - 0x06, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, - 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x2a, 0x0a, 0x04, 0x66, 0x72, - 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x78, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x73, - 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x26, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, - 0x65, 0x78, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x73, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x36, - 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, - 0x75, 0x74, 0x65, 0x64, 0x41, 0x74, 0x1a, 0xab, 0x04, 0x0a, 0x05, 0x53, 0x74, 0x79, 0x6c, 0x65, + 0x64, 0x41, 0x74, 0x1a, 0x5d, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, + 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x2b, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, + 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x1a, 0xe1, 0x04, 0x0a, 0x09, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x64, 0x41, 0x74, 0x12, 0x2a, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x16, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, - 0x78, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x73, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, - 0x26, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x79, 0x6f, - 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x78, 0x74, 0x4e, 0x6f, 0x64, 0x65, - 0x50, 0x6f, 0x73, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x4a, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, - 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x79, 0x6f, - 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, - 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, - 0x74, 0x65, 0x73, 0x12, 0x36, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, - 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, - 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x69, 0x0a, 0x17, 0x63, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x61, 0x70, 0x5f, 0x62, 0x79, - 0x5f, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x79, - 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, - 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x13, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, - 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, - 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x5d, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, - 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x6b, 0x65, 0x79, 0x12, 0x2b, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, - 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x3a, 0x02, 0x38, 0x01, 0x1a, 0xb9, 0x01, 0x0a, 0x08, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x61, 0x73, - 0x65, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, - 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, - 0x6b, 0x65, 0x74, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x64, 0x41, 0x74, 0x12, 0x32, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x4a, 0x53, 0x4f, 0x4e, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x69, 0x6d, 0x70, 0x6c, - 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x36, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, - 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, - 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, - 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, 0x74, - 0x1a, 0xf1, 0x03, 0x0a, 0x08, 0x54, 0x72, 0x65, 0x65, 0x45, 0x64, 0x69, 0x74, 0x12, 0x41, 0x0a, - 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, - 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, - 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, - 0x12, 0x26, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, - 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x50, - 0x6f, 0x73, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x22, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x54, 0x72, 0x65, 0x65, 0x50, 0x6f, 0x73, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x6c, 0x0a, 0x17, - 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x61, 0x70, 0x5f, 0x62, - 0x79, 0x5f, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, - 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x45, 0x64, 0x69, 0x74, 0x2e, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x13, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, - 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x30, 0x0a, 0x08, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x79, - 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, - 0x65, 0x73, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1f, 0x0a, 0x0b, - 0x73, 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x0a, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x36, 0x0a, - 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, - 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, - 0x74, 0x65, 0x64, 0x41, 0x74, 0x1a, 0x5d, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, - 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x6b, 0x65, 0x79, 0x12, 0x2b, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, - 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x3a, 0x02, 0x38, 0x01, 0x1a, 0xe1, 0x04, 0x0a, 0x09, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, 0x79, - 0x6c, 0x65, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, - 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, - 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x26, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x54, 0x72, 0x65, 0x65, 0x50, 0x6f, 0x73, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x22, 0x0a, - 0x02, 0x74, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x79, 0x6f, 0x72, 0x6b, - 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x50, 0x6f, 0x73, 0x52, 0x02, 0x74, - 0x6f, 0x12, 0x4e, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, - 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x54, 0x72, 0x65, 0x65, - 0x53, 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, - 0x73, 0x12, 0x36, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, - 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x30, 0x0a, 0x14, 0x61, 0x74, 0x74, - 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x5f, 0x74, 0x6f, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x76, - 0x65, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, - 0x74, 0x65, 0x73, 0x54, 0x6f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x6d, 0x0a, 0x17, 0x63, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x61, 0x70, 0x5f, 0x62, 0x79, - 0x5f, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x79, - 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x13, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, - 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, - 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, - 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x5d, 0x0a, 0x18, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2b, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x06, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, + 0x64, 0x41, 0x74, 0x12, 0x26, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x12, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, + 0x65, 0x65, 0x50, 0x6f, 0x73, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x22, 0x0a, 0x02, 0x74, + 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x50, 0x6f, 0x73, 0x52, 0x02, 0x74, 0x6f, 0x12, + 0x4e, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, + 0x79, 0x6c, 0x65, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, + 0x36, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x30, 0x0a, 0x14, 0x61, 0x74, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x65, 0x73, 0x5f, 0x74, 0x6f, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x18, + 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, + 0x73, 0x54, 0x6f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x6d, 0x0a, 0x17, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x61, 0x70, 0x5f, 0x62, 0x79, 0x5f, 0x61, + 0x63, 0x74, 0x6f, 0x72, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x79, 0x6f, 0x72, + 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x13, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, + 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x5d, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x64, 0x41, 0x74, 0x4d, 0x61, 0x70, 0x42, 0x79, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2b, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0xef, 0x01, 0x0a, 0x08, 0x41, 0x72, 0x72, 0x61, 0x79, + 0x53, 0x65, 0x74, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, + 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, + 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x34, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, + 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, + 0x74, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x32, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x79, 0x6f, + 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x45, 0x6c, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x12, 0x36, 0x0a, 0x0b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, 0x6b, 0x69, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x0a, 0x65, 0x78, + 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x41, 0x74, 0x42, 0x06, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x22, 0xf1, 0x01, 0x0a, 0x11, 0x4a, 0x53, 0x4f, 0x4e, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x12, 0x34, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x79, 0x6f, 0x72, @@ -4310,7 +4414,7 @@ func file_yorkie_v1_resources_proto_rawDescGZIP() []byte { } var file_yorkie_v1_resources_proto_enumTypes = make([]protoimpl.EnumInfo, 3) -var file_yorkie_v1_resources_proto_msgTypes = make([]protoimpl.MessageInfo, 57) +var file_yorkie_v1_resources_proto_msgTypes = make([]protoimpl.MessageInfo, 58) var file_yorkie_v1_resources_proto_goTypes = []interface{}{ (ValueType)(0), // 0: yorkie.v1.ValueType (DocEventType)(0), // 1: yorkie.v1.DocEventType @@ -4355,25 +4459,26 @@ var file_yorkie_v1_resources_proto_goTypes = []interface{}{ (*Operation_Increase)(nil), // 40: yorkie.v1.Operation.Increase (*Operation_TreeEdit)(nil), // 41: yorkie.v1.Operation.TreeEdit (*Operation_TreeStyle)(nil), // 42: yorkie.v1.Operation.TreeStyle - nil, // 43: yorkie.v1.Operation.Edit.CreatedAtMapByActorEntry - nil, // 44: yorkie.v1.Operation.Edit.AttributesEntry - nil, // 45: yorkie.v1.Operation.Style.AttributesEntry - nil, // 46: yorkie.v1.Operation.Style.CreatedAtMapByActorEntry - nil, // 47: yorkie.v1.Operation.TreeEdit.CreatedAtMapByActorEntry - nil, // 48: yorkie.v1.Operation.TreeStyle.AttributesEntry - nil, // 49: yorkie.v1.Operation.TreeStyle.CreatedAtMapByActorEntry - (*JSONElement_JSONObject)(nil), // 50: yorkie.v1.JSONElement.JSONObject - (*JSONElement_JSONArray)(nil), // 51: yorkie.v1.JSONElement.JSONArray - (*JSONElement_Primitive)(nil), // 52: yorkie.v1.JSONElement.Primitive - (*JSONElement_Text)(nil), // 53: yorkie.v1.JSONElement.Text - (*JSONElement_Counter)(nil), // 54: yorkie.v1.JSONElement.Counter - (*JSONElement_Tree)(nil), // 55: yorkie.v1.JSONElement.Tree - nil, // 56: yorkie.v1.TextNode.AttributesEntry - nil, // 57: yorkie.v1.TreeNode.AttributesEntry - (*UpdatableProjectFields_AuthWebhookMethods)(nil), // 58: yorkie.v1.UpdatableProjectFields.AuthWebhookMethods - nil, // 59: yorkie.v1.Presence.DataEntry - (*timestamppb.Timestamp)(nil), // 60: google.protobuf.Timestamp - (*wrapperspb.StringValue)(nil), // 61: google.protobuf.StringValue + (*Operation_ArraySet)(nil), // 43: yorkie.v1.Operation.ArraySet + nil, // 44: yorkie.v1.Operation.Edit.CreatedAtMapByActorEntry + nil, // 45: yorkie.v1.Operation.Edit.AttributesEntry + nil, // 46: yorkie.v1.Operation.Style.AttributesEntry + nil, // 47: yorkie.v1.Operation.Style.CreatedAtMapByActorEntry + nil, // 48: yorkie.v1.Operation.TreeEdit.CreatedAtMapByActorEntry + nil, // 49: yorkie.v1.Operation.TreeStyle.AttributesEntry + nil, // 50: yorkie.v1.Operation.TreeStyle.CreatedAtMapByActorEntry + (*JSONElement_JSONObject)(nil), // 51: yorkie.v1.JSONElement.JSONObject + (*JSONElement_JSONArray)(nil), // 52: yorkie.v1.JSONElement.JSONArray + (*JSONElement_Primitive)(nil), // 53: yorkie.v1.JSONElement.Primitive + (*JSONElement_Text)(nil), // 54: yorkie.v1.JSONElement.Text + (*JSONElement_Counter)(nil), // 55: yorkie.v1.JSONElement.Counter + (*JSONElement_Tree)(nil), // 56: yorkie.v1.JSONElement.Tree + nil, // 57: yorkie.v1.TextNode.AttributesEntry + nil, // 58: yorkie.v1.TreeNode.AttributesEntry + (*UpdatableProjectFields_AuthWebhookMethods)(nil), // 59: yorkie.v1.UpdatableProjectFields.AuthWebhookMethods + nil, // 60: yorkie.v1.Presence.DataEntry + (*timestamppb.Timestamp)(nil), // 61: google.protobuf.Timestamp + (*wrapperspb.StringValue)(nil), // 62: google.protobuf.StringValue } var file_yorkie_v1_resources_proto_depIdxs = []int32{ 10, // 0: yorkie.v1.Snapshot.root:type_name -> yorkie.v1.JSONElement @@ -4399,131 +4504,136 @@ var file_yorkie_v1_resources_proto_depIdxs = []int32{ 40, // 20: yorkie.v1.Operation.increase:type_name -> yorkie.v1.Operation.Increase 41, // 21: yorkie.v1.Operation.tree_edit:type_name -> yorkie.v1.Operation.TreeEdit 42, // 22: yorkie.v1.Operation.tree_style:type_name -> yorkie.v1.Operation.TreeStyle - 28, // 23: yorkie.v1.JSONElementSimple.created_at:type_name -> yorkie.v1.TimeTicket - 28, // 24: yorkie.v1.JSONElementSimple.moved_at:type_name -> yorkie.v1.TimeTicket - 28, // 25: yorkie.v1.JSONElementSimple.removed_at:type_name -> yorkie.v1.TimeTicket - 0, // 26: yorkie.v1.JSONElementSimple.type:type_name -> yorkie.v1.ValueType - 50, // 27: yorkie.v1.JSONElement.json_object:type_name -> yorkie.v1.JSONElement.JSONObject - 51, // 28: yorkie.v1.JSONElement.json_array:type_name -> yorkie.v1.JSONElement.JSONArray - 52, // 29: yorkie.v1.JSONElement.primitive:type_name -> yorkie.v1.JSONElement.Primitive - 53, // 30: yorkie.v1.JSONElement.text:type_name -> yorkie.v1.JSONElement.Text - 54, // 31: yorkie.v1.JSONElement.counter:type_name -> yorkie.v1.JSONElement.Counter - 55, // 32: yorkie.v1.JSONElement.tree:type_name -> yorkie.v1.JSONElement.Tree - 10, // 33: yorkie.v1.RHTNode.element:type_name -> yorkie.v1.JSONElement - 12, // 34: yorkie.v1.RGANode.next:type_name -> yorkie.v1.RGANode - 10, // 35: yorkie.v1.RGANode.element:type_name -> yorkie.v1.JSONElement - 28, // 36: yorkie.v1.NodeAttr.updated_at:type_name -> yorkie.v1.TimeTicket - 15, // 37: yorkie.v1.TextNode.id:type_name -> yorkie.v1.TextNodeID - 28, // 38: yorkie.v1.TextNode.removed_at:type_name -> yorkie.v1.TimeTicket - 15, // 39: yorkie.v1.TextNode.ins_prev_id:type_name -> yorkie.v1.TextNodeID - 56, // 40: yorkie.v1.TextNode.attributes:type_name -> yorkie.v1.TextNode.AttributesEntry - 28, // 41: yorkie.v1.TextNodeID.created_at:type_name -> yorkie.v1.TimeTicket - 18, // 42: yorkie.v1.TreeNode.id:type_name -> yorkie.v1.TreeNodeID - 28, // 43: yorkie.v1.TreeNode.removed_at:type_name -> yorkie.v1.TimeTicket - 18, // 44: yorkie.v1.TreeNode.ins_prev_id:type_name -> yorkie.v1.TreeNodeID - 18, // 45: yorkie.v1.TreeNode.ins_next_id:type_name -> yorkie.v1.TreeNodeID - 57, // 46: yorkie.v1.TreeNode.attributes:type_name -> yorkie.v1.TreeNode.AttributesEntry - 16, // 47: yorkie.v1.TreeNodes.content:type_name -> yorkie.v1.TreeNode - 28, // 48: yorkie.v1.TreeNodeID.created_at:type_name -> yorkie.v1.TimeTicket - 18, // 49: yorkie.v1.TreePos.parent_id:type_name -> yorkie.v1.TreeNodeID - 18, // 50: yorkie.v1.TreePos.left_sibling_id:type_name -> yorkie.v1.TreeNodeID - 60, // 51: yorkie.v1.User.created_at:type_name -> google.protobuf.Timestamp - 60, // 52: yorkie.v1.Project.created_at:type_name -> google.protobuf.Timestamp - 60, // 53: yorkie.v1.Project.updated_at:type_name -> google.protobuf.Timestamp - 61, // 54: yorkie.v1.UpdatableProjectFields.name:type_name -> google.protobuf.StringValue - 61, // 55: yorkie.v1.UpdatableProjectFields.auth_webhook_url:type_name -> google.protobuf.StringValue - 58, // 56: yorkie.v1.UpdatableProjectFields.auth_webhook_methods:type_name -> yorkie.v1.UpdatableProjectFields.AuthWebhookMethods - 61, // 57: yorkie.v1.UpdatableProjectFields.client_deactivate_threshold:type_name -> google.protobuf.StringValue - 60, // 58: yorkie.v1.DocumentSummary.created_at:type_name -> google.protobuf.Timestamp - 60, // 59: yorkie.v1.DocumentSummary.accessed_at:type_name -> google.protobuf.Timestamp - 60, // 60: yorkie.v1.DocumentSummary.updated_at:type_name -> google.protobuf.Timestamp - 2, // 61: yorkie.v1.PresenceChange.type:type_name -> yorkie.v1.PresenceChange.ChangeType - 25, // 62: yorkie.v1.PresenceChange.presence:type_name -> yorkie.v1.Presence - 59, // 63: yorkie.v1.Presence.data:type_name -> yorkie.v1.Presence.DataEntry - 28, // 64: yorkie.v1.TextNodePos.created_at:type_name -> yorkie.v1.TimeTicket - 1, // 65: yorkie.v1.DocEvent.type:type_name -> yorkie.v1.DocEventType - 29, // 66: yorkie.v1.DocEvent.body:type_name -> yorkie.v1.DocEventBody - 25, // 67: yorkie.v1.Snapshot.PresencesEntry.value:type_name -> yorkie.v1.Presence - 28, // 68: yorkie.v1.Operation.Set.parent_created_at:type_name -> yorkie.v1.TimeTicket - 9, // 69: yorkie.v1.Operation.Set.value:type_name -> yorkie.v1.JSONElementSimple - 28, // 70: yorkie.v1.Operation.Set.executed_at:type_name -> yorkie.v1.TimeTicket - 28, // 71: yorkie.v1.Operation.Add.parent_created_at:type_name -> yorkie.v1.TimeTicket - 28, // 72: yorkie.v1.Operation.Add.prev_created_at:type_name -> yorkie.v1.TimeTicket - 9, // 73: yorkie.v1.Operation.Add.value:type_name -> yorkie.v1.JSONElementSimple - 28, // 74: yorkie.v1.Operation.Add.executed_at:type_name -> yorkie.v1.TimeTicket - 28, // 75: yorkie.v1.Operation.Move.parent_created_at:type_name -> yorkie.v1.TimeTicket - 28, // 76: yorkie.v1.Operation.Move.prev_created_at:type_name -> yorkie.v1.TimeTicket - 28, // 77: yorkie.v1.Operation.Move.created_at:type_name -> yorkie.v1.TimeTicket - 28, // 78: yorkie.v1.Operation.Move.executed_at:type_name -> yorkie.v1.TimeTicket - 28, // 79: yorkie.v1.Operation.Remove.parent_created_at:type_name -> yorkie.v1.TimeTicket - 28, // 80: yorkie.v1.Operation.Remove.created_at:type_name -> yorkie.v1.TimeTicket - 28, // 81: yorkie.v1.Operation.Remove.executed_at:type_name -> yorkie.v1.TimeTicket - 28, // 82: yorkie.v1.Operation.Edit.parent_created_at:type_name -> yorkie.v1.TimeTicket - 27, // 83: yorkie.v1.Operation.Edit.from:type_name -> yorkie.v1.TextNodePos - 27, // 84: yorkie.v1.Operation.Edit.to:type_name -> yorkie.v1.TextNodePos - 43, // 85: yorkie.v1.Operation.Edit.created_at_map_by_actor:type_name -> yorkie.v1.Operation.Edit.CreatedAtMapByActorEntry - 28, // 86: yorkie.v1.Operation.Edit.executed_at:type_name -> yorkie.v1.TimeTicket - 44, // 87: yorkie.v1.Operation.Edit.attributes:type_name -> yorkie.v1.Operation.Edit.AttributesEntry - 28, // 88: yorkie.v1.Operation.Select.parent_created_at:type_name -> yorkie.v1.TimeTicket - 27, // 89: yorkie.v1.Operation.Select.from:type_name -> yorkie.v1.TextNodePos - 27, // 90: yorkie.v1.Operation.Select.to:type_name -> yorkie.v1.TextNodePos - 28, // 91: yorkie.v1.Operation.Select.executed_at:type_name -> yorkie.v1.TimeTicket - 28, // 92: yorkie.v1.Operation.Style.parent_created_at:type_name -> yorkie.v1.TimeTicket - 27, // 93: yorkie.v1.Operation.Style.from:type_name -> yorkie.v1.TextNodePos - 27, // 94: yorkie.v1.Operation.Style.to:type_name -> yorkie.v1.TextNodePos - 45, // 95: yorkie.v1.Operation.Style.attributes:type_name -> yorkie.v1.Operation.Style.AttributesEntry - 28, // 96: yorkie.v1.Operation.Style.executed_at:type_name -> yorkie.v1.TimeTicket - 46, // 97: yorkie.v1.Operation.Style.created_at_map_by_actor:type_name -> yorkie.v1.Operation.Style.CreatedAtMapByActorEntry - 28, // 98: yorkie.v1.Operation.Increase.parent_created_at:type_name -> yorkie.v1.TimeTicket - 9, // 99: yorkie.v1.Operation.Increase.value:type_name -> yorkie.v1.JSONElementSimple - 28, // 100: yorkie.v1.Operation.Increase.executed_at:type_name -> yorkie.v1.TimeTicket - 28, // 101: yorkie.v1.Operation.TreeEdit.parent_created_at:type_name -> yorkie.v1.TimeTicket - 19, // 102: yorkie.v1.Operation.TreeEdit.from:type_name -> yorkie.v1.TreePos - 19, // 103: yorkie.v1.Operation.TreeEdit.to:type_name -> yorkie.v1.TreePos - 47, // 104: yorkie.v1.Operation.TreeEdit.created_at_map_by_actor:type_name -> yorkie.v1.Operation.TreeEdit.CreatedAtMapByActorEntry - 17, // 105: yorkie.v1.Operation.TreeEdit.contents:type_name -> yorkie.v1.TreeNodes - 28, // 106: yorkie.v1.Operation.TreeEdit.executed_at:type_name -> yorkie.v1.TimeTicket - 28, // 107: yorkie.v1.Operation.TreeStyle.parent_created_at:type_name -> yorkie.v1.TimeTicket - 19, // 108: yorkie.v1.Operation.TreeStyle.from:type_name -> yorkie.v1.TreePos - 19, // 109: yorkie.v1.Operation.TreeStyle.to:type_name -> yorkie.v1.TreePos - 48, // 110: yorkie.v1.Operation.TreeStyle.attributes:type_name -> yorkie.v1.Operation.TreeStyle.AttributesEntry - 28, // 111: yorkie.v1.Operation.TreeStyle.executed_at:type_name -> yorkie.v1.TimeTicket - 49, // 112: yorkie.v1.Operation.TreeStyle.created_at_map_by_actor:type_name -> yorkie.v1.Operation.TreeStyle.CreatedAtMapByActorEntry - 28, // 113: yorkie.v1.Operation.Edit.CreatedAtMapByActorEntry.value:type_name -> yorkie.v1.TimeTicket - 28, // 114: yorkie.v1.Operation.Style.CreatedAtMapByActorEntry.value:type_name -> yorkie.v1.TimeTicket - 28, // 115: yorkie.v1.Operation.TreeEdit.CreatedAtMapByActorEntry.value:type_name -> yorkie.v1.TimeTicket - 28, // 116: yorkie.v1.Operation.TreeStyle.CreatedAtMapByActorEntry.value:type_name -> yorkie.v1.TimeTicket - 11, // 117: yorkie.v1.JSONElement.JSONObject.nodes:type_name -> yorkie.v1.RHTNode - 28, // 118: yorkie.v1.JSONElement.JSONObject.created_at:type_name -> yorkie.v1.TimeTicket - 28, // 119: yorkie.v1.JSONElement.JSONObject.moved_at:type_name -> yorkie.v1.TimeTicket - 28, // 120: yorkie.v1.JSONElement.JSONObject.removed_at:type_name -> yorkie.v1.TimeTicket - 12, // 121: yorkie.v1.JSONElement.JSONArray.nodes:type_name -> yorkie.v1.RGANode - 28, // 122: yorkie.v1.JSONElement.JSONArray.created_at:type_name -> yorkie.v1.TimeTicket - 28, // 123: yorkie.v1.JSONElement.JSONArray.moved_at:type_name -> yorkie.v1.TimeTicket - 28, // 124: yorkie.v1.JSONElement.JSONArray.removed_at:type_name -> yorkie.v1.TimeTicket - 0, // 125: yorkie.v1.JSONElement.Primitive.type:type_name -> yorkie.v1.ValueType - 28, // 126: yorkie.v1.JSONElement.Primitive.created_at:type_name -> yorkie.v1.TimeTicket - 28, // 127: yorkie.v1.JSONElement.Primitive.moved_at:type_name -> yorkie.v1.TimeTicket - 28, // 128: yorkie.v1.JSONElement.Primitive.removed_at:type_name -> yorkie.v1.TimeTicket - 14, // 129: yorkie.v1.JSONElement.Text.nodes:type_name -> yorkie.v1.TextNode - 28, // 130: yorkie.v1.JSONElement.Text.created_at:type_name -> yorkie.v1.TimeTicket - 28, // 131: yorkie.v1.JSONElement.Text.moved_at:type_name -> yorkie.v1.TimeTicket - 28, // 132: yorkie.v1.JSONElement.Text.removed_at:type_name -> yorkie.v1.TimeTicket - 0, // 133: yorkie.v1.JSONElement.Counter.type:type_name -> yorkie.v1.ValueType - 28, // 134: yorkie.v1.JSONElement.Counter.created_at:type_name -> yorkie.v1.TimeTicket - 28, // 135: yorkie.v1.JSONElement.Counter.moved_at:type_name -> yorkie.v1.TimeTicket - 28, // 136: yorkie.v1.JSONElement.Counter.removed_at:type_name -> yorkie.v1.TimeTicket - 16, // 137: yorkie.v1.JSONElement.Tree.nodes:type_name -> yorkie.v1.TreeNode - 28, // 138: yorkie.v1.JSONElement.Tree.created_at:type_name -> yorkie.v1.TimeTicket - 28, // 139: yorkie.v1.JSONElement.Tree.moved_at:type_name -> yorkie.v1.TimeTicket - 28, // 140: yorkie.v1.JSONElement.Tree.removed_at:type_name -> yorkie.v1.TimeTicket - 13, // 141: yorkie.v1.TextNode.AttributesEntry.value:type_name -> yorkie.v1.NodeAttr - 13, // 142: yorkie.v1.TreeNode.AttributesEntry.value:type_name -> yorkie.v1.NodeAttr - 143, // [143:143] is the sub-list for method output_type - 143, // [143:143] is the sub-list for method input_type - 143, // [143:143] is the sub-list for extension type_name - 143, // [143:143] is the sub-list for extension extendee - 0, // [0:143] is the sub-list for field type_name + 43, // 23: yorkie.v1.Operation.array_set:type_name -> yorkie.v1.Operation.ArraySet + 28, // 24: yorkie.v1.JSONElementSimple.created_at:type_name -> yorkie.v1.TimeTicket + 28, // 25: yorkie.v1.JSONElementSimple.moved_at:type_name -> yorkie.v1.TimeTicket + 28, // 26: yorkie.v1.JSONElementSimple.removed_at:type_name -> yorkie.v1.TimeTicket + 0, // 27: yorkie.v1.JSONElementSimple.type:type_name -> yorkie.v1.ValueType + 51, // 28: yorkie.v1.JSONElement.json_object:type_name -> yorkie.v1.JSONElement.JSONObject + 52, // 29: yorkie.v1.JSONElement.json_array:type_name -> yorkie.v1.JSONElement.JSONArray + 53, // 30: yorkie.v1.JSONElement.primitive:type_name -> yorkie.v1.JSONElement.Primitive + 54, // 31: yorkie.v1.JSONElement.text:type_name -> yorkie.v1.JSONElement.Text + 55, // 32: yorkie.v1.JSONElement.counter:type_name -> yorkie.v1.JSONElement.Counter + 56, // 33: yorkie.v1.JSONElement.tree:type_name -> yorkie.v1.JSONElement.Tree + 10, // 34: yorkie.v1.RHTNode.element:type_name -> yorkie.v1.JSONElement + 12, // 35: yorkie.v1.RGANode.next:type_name -> yorkie.v1.RGANode + 10, // 36: yorkie.v1.RGANode.element:type_name -> yorkie.v1.JSONElement + 28, // 37: yorkie.v1.NodeAttr.updated_at:type_name -> yorkie.v1.TimeTicket + 15, // 38: yorkie.v1.TextNode.id:type_name -> yorkie.v1.TextNodeID + 28, // 39: yorkie.v1.TextNode.removed_at:type_name -> yorkie.v1.TimeTicket + 15, // 40: yorkie.v1.TextNode.ins_prev_id:type_name -> yorkie.v1.TextNodeID + 57, // 41: yorkie.v1.TextNode.attributes:type_name -> yorkie.v1.TextNode.AttributesEntry + 28, // 42: yorkie.v1.TextNodeID.created_at:type_name -> yorkie.v1.TimeTicket + 18, // 43: yorkie.v1.TreeNode.id:type_name -> yorkie.v1.TreeNodeID + 28, // 44: yorkie.v1.TreeNode.removed_at:type_name -> yorkie.v1.TimeTicket + 18, // 45: yorkie.v1.TreeNode.ins_prev_id:type_name -> yorkie.v1.TreeNodeID + 18, // 46: yorkie.v1.TreeNode.ins_next_id:type_name -> yorkie.v1.TreeNodeID + 58, // 47: yorkie.v1.TreeNode.attributes:type_name -> yorkie.v1.TreeNode.AttributesEntry + 16, // 48: yorkie.v1.TreeNodes.content:type_name -> yorkie.v1.TreeNode + 28, // 49: yorkie.v1.TreeNodeID.created_at:type_name -> yorkie.v1.TimeTicket + 18, // 50: yorkie.v1.TreePos.parent_id:type_name -> yorkie.v1.TreeNodeID + 18, // 51: yorkie.v1.TreePos.left_sibling_id:type_name -> yorkie.v1.TreeNodeID + 61, // 52: yorkie.v1.User.created_at:type_name -> google.protobuf.Timestamp + 61, // 53: yorkie.v1.Project.created_at:type_name -> google.protobuf.Timestamp + 61, // 54: yorkie.v1.Project.updated_at:type_name -> google.protobuf.Timestamp + 62, // 55: yorkie.v1.UpdatableProjectFields.name:type_name -> google.protobuf.StringValue + 62, // 56: yorkie.v1.UpdatableProjectFields.auth_webhook_url:type_name -> google.protobuf.StringValue + 59, // 57: yorkie.v1.UpdatableProjectFields.auth_webhook_methods:type_name -> yorkie.v1.UpdatableProjectFields.AuthWebhookMethods + 62, // 58: yorkie.v1.UpdatableProjectFields.client_deactivate_threshold:type_name -> google.protobuf.StringValue + 61, // 59: yorkie.v1.DocumentSummary.created_at:type_name -> google.protobuf.Timestamp + 61, // 60: yorkie.v1.DocumentSummary.accessed_at:type_name -> google.protobuf.Timestamp + 61, // 61: yorkie.v1.DocumentSummary.updated_at:type_name -> google.protobuf.Timestamp + 2, // 62: yorkie.v1.PresenceChange.type:type_name -> yorkie.v1.PresenceChange.ChangeType + 25, // 63: yorkie.v1.PresenceChange.presence:type_name -> yorkie.v1.Presence + 60, // 64: yorkie.v1.Presence.data:type_name -> yorkie.v1.Presence.DataEntry + 28, // 65: yorkie.v1.TextNodePos.created_at:type_name -> yorkie.v1.TimeTicket + 1, // 66: yorkie.v1.DocEvent.type:type_name -> yorkie.v1.DocEventType + 29, // 67: yorkie.v1.DocEvent.body:type_name -> yorkie.v1.DocEventBody + 25, // 68: yorkie.v1.Snapshot.PresencesEntry.value:type_name -> yorkie.v1.Presence + 28, // 69: yorkie.v1.Operation.Set.parent_created_at:type_name -> yorkie.v1.TimeTicket + 9, // 70: yorkie.v1.Operation.Set.value:type_name -> yorkie.v1.JSONElementSimple + 28, // 71: yorkie.v1.Operation.Set.executed_at:type_name -> yorkie.v1.TimeTicket + 28, // 72: yorkie.v1.Operation.Add.parent_created_at:type_name -> yorkie.v1.TimeTicket + 28, // 73: yorkie.v1.Operation.Add.prev_created_at:type_name -> yorkie.v1.TimeTicket + 9, // 74: yorkie.v1.Operation.Add.value:type_name -> yorkie.v1.JSONElementSimple + 28, // 75: yorkie.v1.Operation.Add.executed_at:type_name -> yorkie.v1.TimeTicket + 28, // 76: yorkie.v1.Operation.Move.parent_created_at:type_name -> yorkie.v1.TimeTicket + 28, // 77: yorkie.v1.Operation.Move.prev_created_at:type_name -> yorkie.v1.TimeTicket + 28, // 78: yorkie.v1.Operation.Move.created_at:type_name -> yorkie.v1.TimeTicket + 28, // 79: yorkie.v1.Operation.Move.executed_at:type_name -> yorkie.v1.TimeTicket + 28, // 80: yorkie.v1.Operation.Remove.parent_created_at:type_name -> yorkie.v1.TimeTicket + 28, // 81: yorkie.v1.Operation.Remove.created_at:type_name -> yorkie.v1.TimeTicket + 28, // 82: yorkie.v1.Operation.Remove.executed_at:type_name -> yorkie.v1.TimeTicket + 28, // 83: yorkie.v1.Operation.Edit.parent_created_at:type_name -> yorkie.v1.TimeTicket + 27, // 84: yorkie.v1.Operation.Edit.from:type_name -> yorkie.v1.TextNodePos + 27, // 85: yorkie.v1.Operation.Edit.to:type_name -> yorkie.v1.TextNodePos + 44, // 86: yorkie.v1.Operation.Edit.created_at_map_by_actor:type_name -> yorkie.v1.Operation.Edit.CreatedAtMapByActorEntry + 28, // 87: yorkie.v1.Operation.Edit.executed_at:type_name -> yorkie.v1.TimeTicket + 45, // 88: yorkie.v1.Operation.Edit.attributes:type_name -> yorkie.v1.Operation.Edit.AttributesEntry + 28, // 89: yorkie.v1.Operation.Select.parent_created_at:type_name -> yorkie.v1.TimeTicket + 27, // 90: yorkie.v1.Operation.Select.from:type_name -> yorkie.v1.TextNodePos + 27, // 91: yorkie.v1.Operation.Select.to:type_name -> yorkie.v1.TextNodePos + 28, // 92: yorkie.v1.Operation.Select.executed_at:type_name -> yorkie.v1.TimeTicket + 28, // 93: yorkie.v1.Operation.Style.parent_created_at:type_name -> yorkie.v1.TimeTicket + 27, // 94: yorkie.v1.Operation.Style.from:type_name -> yorkie.v1.TextNodePos + 27, // 95: yorkie.v1.Operation.Style.to:type_name -> yorkie.v1.TextNodePos + 46, // 96: yorkie.v1.Operation.Style.attributes:type_name -> yorkie.v1.Operation.Style.AttributesEntry + 28, // 97: yorkie.v1.Operation.Style.executed_at:type_name -> yorkie.v1.TimeTicket + 47, // 98: yorkie.v1.Operation.Style.created_at_map_by_actor:type_name -> yorkie.v1.Operation.Style.CreatedAtMapByActorEntry + 28, // 99: yorkie.v1.Operation.Increase.parent_created_at:type_name -> yorkie.v1.TimeTicket + 9, // 100: yorkie.v1.Operation.Increase.value:type_name -> yorkie.v1.JSONElementSimple + 28, // 101: yorkie.v1.Operation.Increase.executed_at:type_name -> yorkie.v1.TimeTicket + 28, // 102: yorkie.v1.Operation.TreeEdit.parent_created_at:type_name -> yorkie.v1.TimeTicket + 19, // 103: yorkie.v1.Operation.TreeEdit.from:type_name -> yorkie.v1.TreePos + 19, // 104: yorkie.v1.Operation.TreeEdit.to:type_name -> yorkie.v1.TreePos + 48, // 105: yorkie.v1.Operation.TreeEdit.created_at_map_by_actor:type_name -> yorkie.v1.Operation.TreeEdit.CreatedAtMapByActorEntry + 17, // 106: yorkie.v1.Operation.TreeEdit.contents:type_name -> yorkie.v1.TreeNodes + 28, // 107: yorkie.v1.Operation.TreeEdit.executed_at:type_name -> yorkie.v1.TimeTicket + 28, // 108: yorkie.v1.Operation.TreeStyle.parent_created_at:type_name -> yorkie.v1.TimeTicket + 19, // 109: yorkie.v1.Operation.TreeStyle.from:type_name -> yorkie.v1.TreePos + 19, // 110: yorkie.v1.Operation.TreeStyle.to:type_name -> yorkie.v1.TreePos + 49, // 111: yorkie.v1.Operation.TreeStyle.attributes:type_name -> yorkie.v1.Operation.TreeStyle.AttributesEntry + 28, // 112: yorkie.v1.Operation.TreeStyle.executed_at:type_name -> yorkie.v1.TimeTicket + 50, // 113: yorkie.v1.Operation.TreeStyle.created_at_map_by_actor:type_name -> yorkie.v1.Operation.TreeStyle.CreatedAtMapByActorEntry + 28, // 114: yorkie.v1.Operation.ArraySet.parent_created_at:type_name -> yorkie.v1.TimeTicket + 28, // 115: yorkie.v1.Operation.ArraySet.created_at:type_name -> yorkie.v1.TimeTicket + 9, // 116: yorkie.v1.Operation.ArraySet.value:type_name -> yorkie.v1.JSONElementSimple + 28, // 117: yorkie.v1.Operation.ArraySet.executed_at:type_name -> yorkie.v1.TimeTicket + 28, // 118: yorkie.v1.Operation.Edit.CreatedAtMapByActorEntry.value:type_name -> yorkie.v1.TimeTicket + 28, // 119: yorkie.v1.Operation.Style.CreatedAtMapByActorEntry.value:type_name -> yorkie.v1.TimeTicket + 28, // 120: yorkie.v1.Operation.TreeEdit.CreatedAtMapByActorEntry.value:type_name -> yorkie.v1.TimeTicket + 28, // 121: yorkie.v1.Operation.TreeStyle.CreatedAtMapByActorEntry.value:type_name -> yorkie.v1.TimeTicket + 11, // 122: yorkie.v1.JSONElement.JSONObject.nodes:type_name -> yorkie.v1.RHTNode + 28, // 123: yorkie.v1.JSONElement.JSONObject.created_at:type_name -> yorkie.v1.TimeTicket + 28, // 124: yorkie.v1.JSONElement.JSONObject.moved_at:type_name -> yorkie.v1.TimeTicket + 28, // 125: yorkie.v1.JSONElement.JSONObject.removed_at:type_name -> yorkie.v1.TimeTicket + 12, // 126: yorkie.v1.JSONElement.JSONArray.nodes:type_name -> yorkie.v1.RGANode + 28, // 127: yorkie.v1.JSONElement.JSONArray.created_at:type_name -> yorkie.v1.TimeTicket + 28, // 128: yorkie.v1.JSONElement.JSONArray.moved_at:type_name -> yorkie.v1.TimeTicket + 28, // 129: yorkie.v1.JSONElement.JSONArray.removed_at:type_name -> yorkie.v1.TimeTicket + 0, // 130: yorkie.v1.JSONElement.Primitive.type:type_name -> yorkie.v1.ValueType + 28, // 131: yorkie.v1.JSONElement.Primitive.created_at:type_name -> yorkie.v1.TimeTicket + 28, // 132: yorkie.v1.JSONElement.Primitive.moved_at:type_name -> yorkie.v1.TimeTicket + 28, // 133: yorkie.v1.JSONElement.Primitive.removed_at:type_name -> yorkie.v1.TimeTicket + 14, // 134: yorkie.v1.JSONElement.Text.nodes:type_name -> yorkie.v1.TextNode + 28, // 135: yorkie.v1.JSONElement.Text.created_at:type_name -> yorkie.v1.TimeTicket + 28, // 136: yorkie.v1.JSONElement.Text.moved_at:type_name -> yorkie.v1.TimeTicket + 28, // 137: yorkie.v1.JSONElement.Text.removed_at:type_name -> yorkie.v1.TimeTicket + 0, // 138: yorkie.v1.JSONElement.Counter.type:type_name -> yorkie.v1.ValueType + 28, // 139: yorkie.v1.JSONElement.Counter.created_at:type_name -> yorkie.v1.TimeTicket + 28, // 140: yorkie.v1.JSONElement.Counter.moved_at:type_name -> yorkie.v1.TimeTicket + 28, // 141: yorkie.v1.JSONElement.Counter.removed_at:type_name -> yorkie.v1.TimeTicket + 16, // 142: yorkie.v1.JSONElement.Tree.nodes:type_name -> yorkie.v1.TreeNode + 28, // 143: yorkie.v1.JSONElement.Tree.created_at:type_name -> yorkie.v1.TimeTicket + 28, // 144: yorkie.v1.JSONElement.Tree.moved_at:type_name -> yorkie.v1.TimeTicket + 28, // 145: yorkie.v1.JSONElement.Tree.removed_at:type_name -> yorkie.v1.TimeTicket + 13, // 146: yorkie.v1.TextNode.AttributesEntry.value:type_name -> yorkie.v1.NodeAttr + 13, // 147: yorkie.v1.TreeNode.AttributesEntry.value:type_name -> yorkie.v1.NodeAttr + 148, // [148:148] is the sub-list for method output_type + 148, // [148:148] is the sub-list for method input_type + 148, // [148:148] is the sub-list for extension type_name + 148, // [148:148] is the sub-list for extension extendee + 0, // [0:148] is the sub-list for field type_name } func init() { file_yorkie_v1_resources_proto_init() } @@ -4988,8 +5098,8 @@ func file_yorkie_v1_resources_proto_init() { return nil } } - file_yorkie_v1_resources_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JSONElement_JSONObject); i { + file_yorkie_v1_resources_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Operation_ArraySet); i { case 0: return &v.state case 1: @@ -5001,7 +5111,7 @@ func file_yorkie_v1_resources_proto_init() { } } file_yorkie_v1_resources_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JSONElement_JSONArray); i { + switch v := v.(*JSONElement_JSONObject); i { case 0: return &v.state case 1: @@ -5013,7 +5123,7 @@ func file_yorkie_v1_resources_proto_init() { } } file_yorkie_v1_resources_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JSONElement_Primitive); i { + switch v := v.(*JSONElement_JSONArray); i { case 0: return &v.state case 1: @@ -5025,7 +5135,7 @@ func file_yorkie_v1_resources_proto_init() { } } file_yorkie_v1_resources_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JSONElement_Text); i { + switch v := v.(*JSONElement_Primitive); i { case 0: return &v.state case 1: @@ -5037,7 +5147,7 @@ func file_yorkie_v1_resources_proto_init() { } } file_yorkie_v1_resources_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JSONElement_Counter); i { + switch v := v.(*JSONElement_Text); i { case 0: return &v.state case 1: @@ -5049,6 +5159,18 @@ func file_yorkie_v1_resources_proto_init() { } } file_yorkie_v1_resources_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*JSONElement_Counter); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_yorkie_v1_resources_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*JSONElement_Tree); i { case 0: return &v.state @@ -5060,7 +5182,7 @@ func file_yorkie_v1_resources_proto_init() { return nil } } - file_yorkie_v1_resources_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { + file_yorkie_v1_resources_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*UpdatableProjectFields_AuthWebhookMethods); i { case 0: return &v.state @@ -5084,6 +5206,7 @@ func file_yorkie_v1_resources_proto_init() { (*Operation_Increase_)(nil), (*Operation_TreeEdit_)(nil), (*Operation_TreeStyle_)(nil), + (*Operation_ArraySet_)(nil), } file_yorkie_v1_resources_proto_msgTypes[7].OneofWrappers = []interface{}{ (*JSONElement_JsonObject)(nil), @@ -5099,7 +5222,7 @@ func file_yorkie_v1_resources_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_yorkie_v1_resources_proto_rawDesc, NumEnums: 3, - NumMessages: 57, + NumMessages: 58, NumExtensions: 0, NumServices: 0, }, diff --git a/api/yorkie/v1/resources.proto b/api/yorkie/v1/resources.proto index a33c5426b..eb0539f8b 100644 --- a/api/yorkie/v1/resources.proto +++ b/api/yorkie/v1/resources.proto @@ -144,6 +144,12 @@ message Operation { repeated string attributes_to_remove = 6; map created_at_map_by_actor = 7; } + message ArraySet { + TimeTicket parent_created_at = 1; + TimeTicket created_at = 2; + JSONElementSimple value = 3; + TimeTicket executed_at = 4; + } oneof body { Set set = 1; @@ -156,6 +162,7 @@ message Operation { Increase increase = 8; TreeEdit tree_edit = 9; TreeStyle tree_style = 10; + ArraySet array_set = 11; } } diff --git a/api/yorkie/v1/v1connect/admin.connect.go b/api/yorkie/v1/v1connect/admin.connect.go index f3d5bb4d6..736acab2e 100644 --- a/api/yorkie/v1/v1connect/admin.connect.go +++ b/api/yorkie/v1/v1connect/admin.connect.go @@ -52,6 +52,12 @@ const ( AdminServiceSignUpProcedure = "/yorkie.v1.AdminService/SignUp" // AdminServiceLogInProcedure is the fully-qualified name of the AdminService's LogIn RPC. AdminServiceLogInProcedure = "/yorkie.v1.AdminService/LogIn" + // AdminServiceDeleteAccountProcedure is the fully-qualified name of the AdminService's + // DeleteAccount RPC. + AdminServiceDeleteAccountProcedure = "/yorkie.v1.AdminService/DeleteAccount" + // AdminServiceChangePasswordProcedure is the fully-qualified name of the AdminService's + // ChangePassword RPC. + AdminServiceChangePasswordProcedure = "/yorkie.v1.AdminService/ChangePassword" // AdminServiceCreateProjectProcedure is the fully-qualified name of the AdminService's // CreateProject RPC. AdminServiceCreateProjectProcedure = "/yorkie.v1.AdminService/CreateProject" @@ -84,12 +90,17 @@ const ( // AdminServiceListChangesProcedure is the fully-qualified name of the AdminService's ListChanges // RPC. AdminServiceListChangesProcedure = "/yorkie.v1.AdminService/ListChanges" + // AdminServiceGetServerVersionProcedure is the fully-qualified name of the AdminService's + // GetServerVersion RPC. + AdminServiceGetServerVersionProcedure = "/yorkie.v1.AdminService/GetServerVersion" ) // AdminServiceClient is a client for the yorkie.v1.AdminService service. type AdminServiceClient interface { SignUp(context.Context, *connect.Request[v1.SignUpRequest]) (*connect.Response[v1.SignUpResponse], error) LogIn(context.Context, *connect.Request[v1.LogInRequest]) (*connect.Response[v1.LogInResponse], error) + DeleteAccount(context.Context, *connect.Request[v1.DeleteAccountRequest]) (*connect.Response[v1.DeleteAccountResponse], error) + ChangePassword(context.Context, *connect.Request[v1.ChangePasswordRequest]) (*connect.Response[v1.ChangePasswordResponse], error) CreateProject(context.Context, *connect.Request[v1.CreateProjectRequest]) (*connect.Response[v1.CreateProjectResponse], error) ListProjects(context.Context, *connect.Request[v1.ListProjectsRequest]) (*connect.Response[v1.ListProjectsResponse], error) GetProject(context.Context, *connect.Request[v1.GetProjectRequest]) (*connect.Response[v1.GetProjectResponse], error) @@ -101,6 +112,7 @@ type AdminServiceClient interface { GetSnapshotMeta(context.Context, *connect.Request[v1.GetSnapshotMetaRequest]) (*connect.Response[v1.GetSnapshotMetaResponse], error) SearchDocuments(context.Context, *connect.Request[v1.SearchDocumentsRequest]) (*connect.Response[v1.SearchDocumentsResponse], error) ListChanges(context.Context, *connect.Request[v1.ListChangesRequest]) (*connect.Response[v1.ListChangesResponse], error) + GetServerVersion(context.Context, *connect.Request[v1.GetServerVersionRequest]) (*connect.Response[v1.GetServerVersionResponse], error) } // NewAdminServiceClient constructs a client for the yorkie.v1.AdminService service. By default, it @@ -123,6 +135,16 @@ func NewAdminServiceClient(httpClient connect.HTTPClient, baseURL string, opts . baseURL+AdminServiceLogInProcedure, opts..., ), + deleteAccount: connect.NewClient[v1.DeleteAccountRequest, v1.DeleteAccountResponse]( + httpClient, + baseURL+AdminServiceDeleteAccountProcedure, + opts..., + ), + changePassword: connect.NewClient[v1.ChangePasswordRequest, v1.ChangePasswordResponse]( + httpClient, + baseURL+AdminServiceChangePasswordProcedure, + opts..., + ), createProject: connect.NewClient[v1.CreateProjectRequest, v1.CreateProjectResponse]( httpClient, baseURL+AdminServiceCreateProjectProcedure, @@ -178,6 +200,11 @@ func NewAdminServiceClient(httpClient connect.HTTPClient, baseURL string, opts . baseURL+AdminServiceListChangesProcedure, opts..., ), + getServerVersion: connect.NewClient[v1.GetServerVersionRequest, v1.GetServerVersionResponse]( + httpClient, + baseURL+AdminServiceGetServerVersionProcedure, + opts..., + ), } } @@ -185,6 +212,8 @@ func NewAdminServiceClient(httpClient connect.HTTPClient, baseURL string, opts . type adminServiceClient struct { signUp *connect.Client[v1.SignUpRequest, v1.SignUpResponse] logIn *connect.Client[v1.LogInRequest, v1.LogInResponse] + deleteAccount *connect.Client[v1.DeleteAccountRequest, v1.DeleteAccountResponse] + changePassword *connect.Client[v1.ChangePasswordRequest, v1.ChangePasswordResponse] createProject *connect.Client[v1.CreateProjectRequest, v1.CreateProjectResponse] listProjects *connect.Client[v1.ListProjectsRequest, v1.ListProjectsResponse] getProject *connect.Client[v1.GetProjectRequest, v1.GetProjectResponse] @@ -196,6 +225,7 @@ type adminServiceClient struct { getSnapshotMeta *connect.Client[v1.GetSnapshotMetaRequest, v1.GetSnapshotMetaResponse] searchDocuments *connect.Client[v1.SearchDocumentsRequest, v1.SearchDocumentsResponse] listChanges *connect.Client[v1.ListChangesRequest, v1.ListChangesResponse] + getServerVersion *connect.Client[v1.GetServerVersionRequest, v1.GetServerVersionResponse] } // SignUp calls yorkie.v1.AdminService.SignUp. @@ -208,6 +238,16 @@ func (c *adminServiceClient) LogIn(ctx context.Context, req *connect.Request[v1. return c.logIn.CallUnary(ctx, req) } +// DeleteAccount calls yorkie.v1.AdminService.DeleteAccount. +func (c *adminServiceClient) DeleteAccount(ctx context.Context, req *connect.Request[v1.DeleteAccountRequest]) (*connect.Response[v1.DeleteAccountResponse], error) { + return c.deleteAccount.CallUnary(ctx, req) +} + +// ChangePassword calls yorkie.v1.AdminService.ChangePassword. +func (c *adminServiceClient) ChangePassword(ctx context.Context, req *connect.Request[v1.ChangePasswordRequest]) (*connect.Response[v1.ChangePasswordResponse], error) { + return c.changePassword.CallUnary(ctx, req) +} + // CreateProject calls yorkie.v1.AdminService.CreateProject. func (c *adminServiceClient) CreateProject(ctx context.Context, req *connect.Request[v1.CreateProjectRequest]) (*connect.Response[v1.CreateProjectResponse], error) { return c.createProject.CallUnary(ctx, req) @@ -263,10 +303,17 @@ func (c *adminServiceClient) ListChanges(ctx context.Context, req *connect.Reque return c.listChanges.CallUnary(ctx, req) } +// GetServerVersion calls yorkie.v1.AdminService.GetServerVersion. +func (c *adminServiceClient) GetServerVersion(ctx context.Context, req *connect.Request[v1.GetServerVersionRequest]) (*connect.Response[v1.GetServerVersionResponse], error) { + return c.getServerVersion.CallUnary(ctx, req) +} + // AdminServiceHandler is an implementation of the yorkie.v1.AdminService service. type AdminServiceHandler interface { SignUp(context.Context, *connect.Request[v1.SignUpRequest]) (*connect.Response[v1.SignUpResponse], error) LogIn(context.Context, *connect.Request[v1.LogInRequest]) (*connect.Response[v1.LogInResponse], error) + DeleteAccount(context.Context, *connect.Request[v1.DeleteAccountRequest]) (*connect.Response[v1.DeleteAccountResponse], error) + ChangePassword(context.Context, *connect.Request[v1.ChangePasswordRequest]) (*connect.Response[v1.ChangePasswordResponse], error) CreateProject(context.Context, *connect.Request[v1.CreateProjectRequest]) (*connect.Response[v1.CreateProjectResponse], error) ListProjects(context.Context, *connect.Request[v1.ListProjectsRequest]) (*connect.Response[v1.ListProjectsResponse], error) GetProject(context.Context, *connect.Request[v1.GetProjectRequest]) (*connect.Response[v1.GetProjectResponse], error) @@ -278,6 +325,7 @@ type AdminServiceHandler interface { GetSnapshotMeta(context.Context, *connect.Request[v1.GetSnapshotMetaRequest]) (*connect.Response[v1.GetSnapshotMetaResponse], error) SearchDocuments(context.Context, *connect.Request[v1.SearchDocumentsRequest]) (*connect.Response[v1.SearchDocumentsResponse], error) ListChanges(context.Context, *connect.Request[v1.ListChangesRequest]) (*connect.Response[v1.ListChangesResponse], error) + GetServerVersion(context.Context, *connect.Request[v1.GetServerVersionRequest]) (*connect.Response[v1.GetServerVersionResponse], error) } // NewAdminServiceHandler builds an HTTP handler from the service implementation. It returns the @@ -296,6 +344,16 @@ func NewAdminServiceHandler(svc AdminServiceHandler, opts ...connect.HandlerOpti svc.LogIn, opts..., ) + adminServiceDeleteAccountHandler := connect.NewUnaryHandler( + AdminServiceDeleteAccountProcedure, + svc.DeleteAccount, + opts..., + ) + adminServiceChangePasswordHandler := connect.NewUnaryHandler( + AdminServiceChangePasswordProcedure, + svc.ChangePassword, + opts..., + ) adminServiceCreateProjectHandler := connect.NewUnaryHandler( AdminServiceCreateProjectProcedure, svc.CreateProject, @@ -351,12 +409,21 @@ func NewAdminServiceHandler(svc AdminServiceHandler, opts ...connect.HandlerOpti svc.ListChanges, opts..., ) + adminServiceGetServerVersionHandler := connect.NewUnaryHandler( + AdminServiceGetServerVersionProcedure, + svc.GetServerVersion, + opts..., + ) return "/yorkie.v1.AdminService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { case AdminServiceSignUpProcedure: adminServiceSignUpHandler.ServeHTTP(w, r) case AdminServiceLogInProcedure: adminServiceLogInHandler.ServeHTTP(w, r) + case AdminServiceDeleteAccountProcedure: + adminServiceDeleteAccountHandler.ServeHTTP(w, r) + case AdminServiceChangePasswordProcedure: + adminServiceChangePasswordHandler.ServeHTTP(w, r) case AdminServiceCreateProjectProcedure: adminServiceCreateProjectHandler.ServeHTTP(w, r) case AdminServiceListProjectsProcedure: @@ -379,6 +446,8 @@ func NewAdminServiceHandler(svc AdminServiceHandler, opts ...connect.HandlerOpti adminServiceSearchDocumentsHandler.ServeHTTP(w, r) case AdminServiceListChangesProcedure: adminServiceListChangesHandler.ServeHTTP(w, r) + case AdminServiceGetServerVersionProcedure: + adminServiceGetServerVersionHandler.ServeHTTP(w, r) default: http.NotFound(w, r) } @@ -396,6 +465,14 @@ func (UnimplementedAdminServiceHandler) LogIn(context.Context, *connect.Request[ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("yorkie.v1.AdminService.LogIn is not implemented")) } +func (UnimplementedAdminServiceHandler) DeleteAccount(context.Context, *connect.Request[v1.DeleteAccountRequest]) (*connect.Response[v1.DeleteAccountResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("yorkie.v1.AdminService.DeleteAccount is not implemented")) +} + +func (UnimplementedAdminServiceHandler) ChangePassword(context.Context, *connect.Request[v1.ChangePasswordRequest]) (*connect.Response[v1.ChangePasswordResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("yorkie.v1.AdminService.ChangePassword is not implemented")) +} + func (UnimplementedAdminServiceHandler) CreateProject(context.Context, *connect.Request[v1.CreateProjectRequest]) (*connect.Response[v1.CreateProjectResponse], error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("yorkie.v1.AdminService.CreateProject is not implemented")) } @@ -439,3 +516,7 @@ func (UnimplementedAdminServiceHandler) SearchDocuments(context.Context, *connec func (UnimplementedAdminServiceHandler) ListChanges(context.Context, *connect.Request[v1.ListChangesRequest]) (*connect.Response[v1.ListChangesResponse], error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("yorkie.v1.AdminService.ListChanges is not implemented")) } + +func (UnimplementedAdminServiceHandler) GetServerVersion(context.Context, *connect.Request[v1.GetServerVersionRequest]) (*connect.Response[v1.GetServerVersionResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("yorkie.v1.AdminService.GetServerVersion is not implemented")) +} diff --git a/build/charts/yorkie-cluster/Chart.yaml b/build/charts/yorkie-cluster/Chart.yaml index 3d0eb1272..15ec0268c 100644 --- a/build/charts/yorkie-cluster/Chart.yaml +++ b/build/charts/yorkie-cluster/Chart.yaml @@ -11,8 +11,8 @@ maintainers: sources: - https://github.com/yorkie-team/yorkie -version: 0.4.27 -appVersion: "0.4.27" +version: 0.4.29 +appVersion: "0.4.29" kubeVersion: ">=1.23.0-0" keywords: diff --git a/build/docker/README.md b/build/docker/README.md index 58e2afb05..28820835c 100644 --- a/build/docker/README.md +++ b/build/docker/README.md @@ -5,18 +5,18 @@ running multi-container Docker applications. We use Docker Compose to run the applications needed during Yorkie development. When developing Yorkie, we can easily run the required dependant applications -through `docker-compose` command. +through `docker compose` command. ```bash -# Run docker-compose up and Compose starts and runs apps. -docker-compose -f docker/docker-compose.yml up --build -d +# Run docker compose up and Compose starts and runs apps. +docker compose -f docker/docker-compose.yml up --build -d # Shut down the apps -docker-compose -f docker/docker-compose.yml down +docker compose -f docker/docker-compose.yml down ``` The docker-compose files we use are as follows: - `docker-compose.yml`: This file is used to run Yorkie's integration tests. It runs MongoDB. -- `docker-compose-full.yml`: This file launches all the applications needed to - develop Yorkie. It also runs monitoring tools such as Prometheus and Grafana. +- `docker-compose-full.yml`: This file builds Yorkie and launches it. It also runs + MongoDB and monitoring tools such as Prometheus and Grafana. diff --git a/build/docker/docker-compose-full.yml b/build/docker/docker-compose-full.yml index c6739062d..b49563f24 100644 --- a/build/docker/docker-compose-full.yml +++ b/build/docker/docker-compose-full.yml @@ -5,16 +5,21 @@ services: image: prom/prometheus:latest container_name: prometheus ports: - - '9090:9090' + - '9090:9090' command: - - --config.file=/etc/prometheus/prometheus.yml + - --config.file=/etc/prometheus/prometheus.yml volumes: - - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro + - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro grafana: image: grafana/grafana:latest container_name: grafana ports: - '3000:3000' + command: + - --config=/etc/grafana/grafana.ini + volumes: + - ./monitoring/grafana.ini:/etc/grafana/grafana.ini:ro + - ./monitoring/datasources.yml:/etc/grafana/provisioning/datasources/datasources.yml:ro depends_on: - prometheus mongo: @@ -23,3 +28,21 @@ services: restart: always ports: - '27017:27017' + yorkie: + build: + context: ../../ + dockerfile: Dockerfile + container_name: 'yorkie' + command: + [ + 'server', + '--mongo-connection-uri', + 'mongodb://mongo:27017', + '--enable-pprof', + ] + restart: always + ports: + - '8080:8080' + - '8081:8081' + depends_on: + - mongo diff --git a/build/docker/monitoring/README.md b/build/docker/monitoring/README.md new file mode 100644 index 000000000..d49d5c0a4 --- /dev/null +++ b/build/docker/monitoring/README.md @@ -0,0 +1,12 @@ +# Grafana Setup Guide + +## Importing Dashboards + +To import dashboards into Grafana, follow these steps: + +1. Open Grafana in your browser ([http://localhost:3000](http://localhost:3000)). +2. Log in with the default credentials (admin/admin). +3. Click "Dashboards" in the left sidebar. +4. Click "New" and then "Import". +5. Use the Yorkie dashboard ID `18560` to import the dashboard. +6. Click "Load" and "Import" and the dashboard will be made. diff --git a/build/docker/monitoring/datasources.yml b/build/docker/monitoring/datasources.yml new file mode 100644 index 000000000..86fd3465e --- /dev/null +++ b/build/docker/monitoring/datasources.yml @@ -0,0 +1,8 @@ +apiVersion: 1 + +datasources: + - name: Prometheus + type: prometheus + access: proxy + url: http://prometheus:9090 + isDefault: true diff --git a/build/docker/monitoring/grafana.ini b/build/docker/monitoring/grafana.ini new file mode 100644 index 000000000..6145316b9 --- /dev/null +++ b/build/docker/monitoring/grafana.ini @@ -0,0 +1,21 @@ +[paths] +provisioning = /etc/grafana/provisioning + +[server] +http_port = 3000 + +[security] +admin_user = admin +admin_password = admin + +[users] +allow_sign_up = true + +[auth.anonymous] +enabled = false + +[dashboards] +versions_to_keep = 20 + +[unified_alerting] +enabled = true diff --git a/build/docker/monitoring/prometheus.yml b/build/docker/monitoring/prometheus.yml new file mode 100644 index 000000000..9cd0205d6 --- /dev/null +++ b/build/docker/monitoring/prometheus.yml @@ -0,0 +1,7 @@ +scrape_configs: +- job_name: yorkie + metrics_path: /metrics + scrape_interval: 5s + static_configs: + - targets: + - yorkie:8081 diff --git a/build/docker/prometheus.yml b/build/docker/prometheus.yml deleted file mode 100644 index 8f9792960..000000000 --- a/build/docker/prometheus.yml +++ /dev/null @@ -1,8 +0,0 @@ -scrape_configs: -- job_name: yorkie - metrics_path: /metrics - scrape_interval: 5s - static_configs: - - targets: - # win/mac hosts: Use address: host.docker.internal instead of address: localhost in the line below - - host.docker.internal:8081 diff --git a/client/client.go b/client/client.go index e3b8c30ed..3f2f082b0 100644 --- a/client/client.go +++ b/client/client.go @@ -344,6 +344,17 @@ func (c *Client) Attach(ctx context.Context, doc *document.Document, options ... } } + if err = doc.Update(func(root *json.Object, p *presence.Presence) error { + for k, v := range opts.InitialRoot { + if root.Get(k) == nil { + root.SetDynamicValue(k, v) + } + } + return nil + }); err != nil { + return err + } + return nil } @@ -781,11 +792,11 @@ func (c *Client) broadcast(ctx context.Context, doc *document.Document, topic st func newTLSConfigFromFile(certFile, serverNameOverride string) (*tls.Config, error) { b, err := os.ReadFile(filepath.Clean(certFile)) if err != nil { - return nil, fmt.Errorf("credentials: failed to read TLS config file %q: %w", certFile, err) + return nil, fmt.Errorf("read TLS config file %q: %w", certFile, err) } cp := x509.NewCertPool() if !cp.AppendCertsFromPEM(b) { - return nil, fmt.Errorf("credentials: failed to append certificates") + return nil, fmt.Errorf("failure to append certs from PEM") } return &tls.Config{ServerName: serverNameOverride, RootCAs: cp, MinVersion: tls.VersionTLS12}, nil diff --git a/client/options.go b/client/options.go index 739264c7d..fcb03b6a9 100644 --- a/client/options.go +++ b/client/options.go @@ -92,8 +92,9 @@ 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 - IsManual bool + Presence innerpresence.Presence + InitialRoot map[string]any + IsManual bool } // WithPresence configures the presence of the client. @@ -101,6 +102,15 @@ func WithPresence(presence innerpresence.Presence) AttachOption { return func(o *AttachOptions) { o.Presence = presence } } +// WithInitialRoot sets the initial root of the document. Values in the initial +// root will be discarded if the key already exists in the document. If some +// keys are not in the document, they will be added. +func WithInitialRoot(root map[string]any) AttachOption { + return func(o *AttachOptions) { + o.InitialRoot = root + } +} + // WithManualSync configures the manual sync of the client. func WithManualSync() AttachOption { return func(o *AttachOptions) { o.IsManual = true } diff --git a/cmd/yorkie/config/config.go b/cmd/yorkie/config/config.go index 37e0fa6ff..687763fa9 100644 --- a/cmd/yorkie/config/config.go +++ b/cmd/yorkie/config/config.go @@ -79,7 +79,7 @@ func LoadAuth(addr string) (Auth, error) { auth, ok := config.Auths[addr] if !ok { - return Auth{}, fmt.Errorf("auth for %s does not exist", addr) + return Auth{}, fmt.Errorf("auth for '%s' does not exist", addr) } return auth, nil diff --git a/cmd/yorkie/delete_account.go b/cmd/yorkie/delete_account.go new file mode 100644 index 000000000..6e1f61273 --- /dev/null +++ b/cmd/yorkie/delete_account.go @@ -0,0 +1,136 @@ +/* + * Copyright 2024 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 main + +import ( + "context" + "fmt" + "time" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/yorkie-team/yorkie/admin" + "github.com/yorkie-team/yorkie/cmd/yorkie/config" +) + +func deleteAccountCmd() *cobra.Command { + return &cobra.Command{ + Use: "delete-account", + Short: "Delete account", + PreRunE: config.Preload, + RunE: func(_ *cobra.Command, args []string) error { + rpcAddr := viper.GetString("rpcAddr") + auth, err := config.LoadAuth(rpcAddr) + if err != nil { + return err + } + + if err := readPassword(); err != nil { + return err + } + + if confirmation, err := makeConfirmation(); !confirmation || err != nil { + if err != nil { + return err + } + return nil + } + + conf, err := config.Load() + if err != nil { + return err + } + + if rpcAddr == "" { + rpcAddr = viper.GetString("rpcAddr") + } + + if err := deleteAccount(conf, auth, rpcAddr, username, password); err != nil { + fmt.Println("Failed to delete account: ", err) + } + + return nil + }, + } +} + +func makeConfirmation() (bool, error) { + fmt.Println("Warning: This action cannot be undone. Type 'DELETE' to confirm: ") + var confirmation string + if _, err := fmt.Scanln(&confirmation); err != nil { + return false, fmt.Errorf("read confirmation from user: %w", err) + } + + if confirmation != "DELETE" { + return false, fmt.Errorf("account deletion aborted") + } + + return true, nil +} + +func deleteAccount(conf *config.Config, auth config.Auth, rpcAddr, username, password string) error { + cli, err := admin.Dial(rpcAddr, admin.WithToken(auth.Token), admin.WithInsecure(auth.Insecure)) + if err != nil { + return err + } + defer func() { + cli.Close() + }() + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + if err := cli.DeleteAccount(ctx, username, password); err != nil { + return fmt.Errorf("delete account: %w", err) + } + + delete(conf.Auths, rpcAddr) + if conf.RPCAddr == rpcAddr { + for addr := range conf.Auths { + conf.RPCAddr = addr + break + } + } + + if err := config.Save(conf); err != nil { + return err + } + + return nil +} + +func init() { + cmd := deleteAccountCmd() + cmd.Flags().StringVarP( + &username, + "username", + "u", + "", + "Username", + ) + cmd.Flags().StringVarP( + &password, + "password", + "p", + "", + "Password (optional)", + ) + + _ = cmd.MarkFlagRequired("username") + rootCmd.AddCommand(cmd) +} diff --git a/cmd/yorkie/login.go b/cmd/yorkie/login.go index da636f0c8..d2626bd15 100644 --- a/cmd/yorkie/login.go +++ b/cmd/yorkie/login.go @@ -18,8 +18,11 @@ package main import ( "context" + "fmt" + "os" "github.com/spf13/cobra" + "golang.org/x/term" "github.com/yorkie-team/yorkie/admin" "github.com/yorkie-team/yorkie/cmd/yorkie/config" @@ -35,9 +38,13 @@ var ( func newLoginCmd() *cobra.Command { return &cobra.Command{ Use: "login", - Short: "Log in to Yorkie server", + Short: "Log in to the Yorkie server", PreRunE: config.Preload, RunE: func(cmd *cobra.Command, args []string) error { + if err := readPassword(); err != nil { + return err + } + cli, err := admin.Dial(rpcAddr, admin.WithInsecure(insecure)) if err != nil { return err @@ -74,6 +81,20 @@ func newLoginCmd() *cobra.Command { } } +// readPassword reads the password from the user. +func readPassword() error { + if password == "" { + fmt.Print("Enter Password: ") + bytePassword, err := term.ReadPassword(int(os.Stdin.Fd())) + if err != nil { + return fmt.Errorf("read password: %w", err) + } + password = string(bytePassword) + fmt.Println() + } + return nil +} + func init() { cmd := newLoginCmd() cmd.Flags().StringVarP( @@ -81,14 +102,14 @@ func init() { "username", "u", "", - "Username (required if password is set)", + "Username", ) cmd.Flags().StringVarP( &password, "password", "p", "", - "Password (required if username is set)", + "Password (optional)", ) cmd.Flags().StringVar( &rpcAddr, @@ -102,6 +123,6 @@ func init() { false, "Skip the TLS connection of the client", ) - cmd.MarkFlagsRequiredTogether("username", "password") + _ = cmd.MarkFlagRequired("username") rootCmd.AddCommand(cmd) } diff --git a/cmd/yorkie/passwd.go b/cmd/yorkie/passwd.go new file mode 100644 index 000000000..0c1200317 --- /dev/null +++ b/cmd/yorkie/passwd.go @@ -0,0 +1,116 @@ +/* + * Copyright 2024 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 main + +import ( + "context" + "fmt" + "os" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + "golang.org/x/term" + + "github.com/yorkie-team/yorkie/admin" + "github.com/yorkie-team/yorkie/cmd/yorkie/config" +) + +func passwdCmd() *cobra.Command { + return &cobra.Command{ + Use: "passwd", + Short: "Change password", + PreRunE: config.Preload, + RunE: func(cmd *cobra.Command, args []string) error { + rpcAddr := viper.GetString("rpcAddr") + auth, err := config.LoadAuth(rpcAddr) + if err != nil { + return err + } + + password, newPassword, err := readPasswords() + if err != nil { + return err + } + + cli, err := admin.Dial(rpcAddr, admin.WithToken(auth.Token), admin.WithInsecure(auth.Insecure)) + if err != nil { + return err + } + defer func() { + cli.Close() + }() + + ctx := context.Background() + if err := cli.ChangePassword(ctx, username, password, newPassword); err != nil { + return err + } + + if err := deleteAuthSession(rpcAddr); err != nil { + return err + } + + return nil + }, + } +} + +func readPasswords() (string, string, error) { + fmt.Print("Enter Password: ") + bytePassword, err := term.ReadPassword(int(os.Stdin.Fd())) + if err != nil { + return "", "", fmt.Errorf("read password: %w", err) + } + password := string(bytePassword) + fmt.Println() + + fmt.Print("Enter New Password: ") + bytePassword, err = term.ReadPassword(int(os.Stdin.Fd())) + if err != nil { + return "", "", fmt.Errorf("read new password: %w", err) + } + newPassword := string(bytePassword) + fmt.Println() + + return password, newPassword, nil +} + +func deleteAuthSession(rpcAddr string) error { + conf, err := config.Load() + if err != nil { + return err + } + + delete(conf.Auths, rpcAddr) + if err := config.Save(conf); err != nil { + return err + } + + return nil +} + +func init() { + cmd := passwdCmd() + cmd.Flags().StringVarP( + &username, + "username", + "u", + "", + "Username", + ) + _ = cmd.MarkFlagRequired("username") + rootCmd.AddCommand(cmd) +} diff --git a/cmd/yorkie/version.go b/cmd/yorkie/version.go index 573249324..7207f76db 100644 --- a/cmd/yorkie/version.go +++ b/cmd/yorkie/version.go @@ -17,27 +17,165 @@ package main import ( - "fmt" + "context" + "encoding/json" + "errors" "runtime" + "connectrpc.com/connect" "github.com/spf13/cobra" + "github.com/spf13/viper" + "gopkg.in/yaml.v3" + "github.com/yorkie-team/yorkie/admin" + "github.com/yorkie-team/yorkie/api/types" + "github.com/yorkie-team/yorkie/cmd/yorkie/config" "github.com/yorkie-team/yorkie/internal/version" ) +var ( + clientOnly bool + output string +) + func newVersionCmd() *cobra.Command { return &cobra.Command{ - Use: "version", - Short: "Print the version number of Yorkie", + Use: "version", + Short: "Print the version number of Yorkie", + PreRunE: config.Preload, RunE: func(cmd *cobra.Command, args []string) error { - fmt.Printf("Yorkie: %s\n", version.Version) - fmt.Printf("Go: %s\n", runtime.Version()) - fmt.Printf("Build date: %s\n", version.BuildDate) + if err := validateOutputOpts(); err != nil { + return err + } + + info := types.VersionInfo{ + ClientVersion: clientVersion(), + } + + var serverErr error + if !clientOnly { + info.ServerVersion, serverErr = fetchServerVersion() + } + + if err := printVersionInfo(cmd, output, &info); err != nil { + return err + } + + if serverErr != nil { + printServerError(cmd, serverErr) + } + return nil }, } } +func fetchServerVersion() (*types.VersionDetail, error) { + rpcAddr := viper.GetString("rpcAddr") + auth, err := config.LoadAuth(rpcAddr) + if err != nil { + return nil, err + } + + cli, err := admin.Dial(rpcAddr, admin.WithToken(auth.Token), admin.WithInsecure(auth.Insecure)) + if err != nil { + return nil, err + } + defer cli.Close() + + sv, err := cli.GetServerVersion(context.Background()) + if err != nil { + return nil, err + } + + return sv, nil +} + +func clientVersion() *types.VersionDetail { + return &types.VersionDetail{ + YorkieVersion: version.Version, + GoVersion: runtime.Version(), + BuildDate: version.BuildDate, + } +} + +func printServerError(cmd *cobra.Command, err error) { + cmd.Print("Error fetching server version: ") + + // TODO(hyun98): Find cases where different error cases can occur, + // and display a user-friendly error message for each case. + // Furthermore, it would be good to improve it by creating a + // general-purpose error handling module for rpc communication. + // For more information, see the following link: + // https://connectrpc.com/docs/go/errors/ + var connectErr *connect.Error + if errors.As(err, &connectErr) && connectErr.Code() == connect.CodeUnimplemented { + cmd.Println("The server does not support this operation. You might need to check your server version.") + return + } + + cmd.Println(err) +} + +func printVersionInfo(cmd *cobra.Command, output string, versionInfo *types.VersionInfo) error { + switch output { + case "": + cmd.Printf("Yorkie Client: %s\n", versionInfo.ClientVersion.YorkieVersion) + cmd.Printf("Go: %s\n", versionInfo.ClientVersion.GoVersion) + cmd.Printf("Build Date: %s\n", versionInfo.ClientVersion.BuildDate) + if versionInfo.ServerVersion != nil { + cmd.Printf("Yorkie Server: %s\n", versionInfo.ServerVersion.YorkieVersion) + cmd.Printf("Go: %s\n", versionInfo.ServerVersion.GoVersion) + cmd.Printf("Build Date: %s\n", versionInfo.ServerVersion.BuildDate) + } + case "yaml": + marshalled, err := yaml.Marshal(versionInfo) + if err != nil { + return errors.New("marshal YAML") + } + cmd.Println(string(marshalled)) + case "json": + marshalled, err := json.MarshalIndent(versionInfo, "", " ") + if err != nil { + return errors.New("marshal JSON") + } + cmd.Println(string(marshalled)) + default: + return errors.New("unknown output format") + } + + return nil +} + +// validateOutputOpts validates the output options. +func validateOutputOpts() error { + if output != "" && output != "yaml" && output != "json" { + return errors.New(`--output must be 'yaml' or 'json'`) + } + + return nil +} + func init() { - rootCmd.AddCommand(newVersionCmd()) + cmd := newVersionCmd() + + cmd.Flags().BoolVar( + &clientOnly, + "client", + clientOnly, + "Shows client version only (no server required).", + ) + + // TODO(hackerwins): Output format should be configurable globally. + // So, we need to move this to the root command like `--rpc-addr` and + // apply it to all subcommands that print output. + cmd.Flags().StringVarP( + &output, + "output", + "o", + output, + "One of 'yaml' or 'json'.", + ) + + rootCmd.AddCommand(cmd) } diff --git a/go.mod b/go.mod index 1b71cea9b..9abb9dd77 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.21 require ( connectrpc.com/connect v1.12.0 connectrpc.com/grpchealth v1.3.0 + github.com/go-co-op/gocron/v2 v2.10.1 github.com/go-playground/locales v0.14.0 github.com/go-playground/universal-translator v0.18.0 github.com/go-playground/validator/v10 v10.11.1 @@ -16,8 +17,8 @@ require ( github.com/rs/xid v1.5.0 github.com/spf13/cobra v1.5.0 github.com/spf13/viper v1.17.0 - github.com/stretchr/testify v1.8.4 - github.com/undefinedlabs/go-mpatch v1.0.6 + github.com/stretchr/testify v1.9.0 + github.com/undefinedlabs/go-mpatch v1.0.7 go.mongodb.org/mongo-driver v1.11.7 go.uber.org/zap v1.23.0 golang.org/x/crypto v0.16.0 @@ -26,8 +27,11 @@ require ( google.golang.org/grpc v1.58.3 google.golang.org/protobuf v1.31.0 gopkg.in/yaml.v2 v2.4.0 + gopkg.in/yaml.v3 v3.0.1 ) +require github.com/stretchr/objx v0.5.2 // indirect + require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect @@ -35,10 +39,12 @@ require ( github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.4 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/jonboulle/clockwork v0.4.0 // indirect github.com/klauspost/compress v1.17.0 // indirect github.com/leodido/go-urn v1.2.1 // indirect github.com/magiconair/properties v1.8.7 // indirect @@ -53,6 +59,7 @@ require ( github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect github.com/rivo/uniseg v0.4.2 // indirect + github.com/robfig/cron/v3 v3.0.1 // indirect github.com/sagikazarmark/locafero v0.3.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect @@ -66,12 +73,12 @@ require ( github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.9.0 // indirect - golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect - golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.15.0 // indirect + golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.23.0 // indirect + golang.org/x/term v0.23.0 golang.org/x/text v0.14.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect ) replace github.com/hashicorp/go-memdb => github.com/hackerwins/go-memdb v1.3.3-0.20211225080334-513a74641622 diff --git a/go.sum b/go.sum index b8ca1bca3..77e3fa764 100644 --- a/go.sum +++ b/go.sum @@ -81,6 +81,8 @@ github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0X github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/go-co-op/gocron/v2 v2.10.1 h1:rlDqSrn+lcMCO4H2d/o+WxpeSTPNkcpW5oaJdeg1pnQ= +github.com/go-co-op/gocron/v2 v2.10.1/go.mod h1:xY7bJxGazKam1cz04EebrlP4S9q4iWdiAylMGP3jY9w= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -148,8 +150,8 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -166,11 +168,11 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/hackerwins/go-memdb v1.3.3-0.20211225080334-513a74641622 h1:7UYuTq6zV83XV4zqn14gUuTtcywzbxGhUnj+hr/MUrE= github.com/hackerwins/go-memdb v1.3.3-0.20211225080334-513a74641622/go.mod h1:uBTr1oQbtuMgd1SSGoR8YV27eT3sBHbYiNm53bMpgSg= github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -191,6 +193,8 @@ github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7P github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jedib0t/go-pretty/v6 v6.4.9 h1:vZ6bjGg2eBSrJn365qlxGcaWu09Id+LHtrfDWlB2Usc= github.com/jedib0t/go-pretty/v6 v6.4.9/go.mod h1:Ndk3ase2CkQbXLLNf5QDHoYb6J9WtVfmHZu9n8rk2xs= +github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= +github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -279,6 +283,8 @@ github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0ua github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8= github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= @@ -312,6 +318,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -321,14 +329,17 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/undefinedlabs/go-mpatch v1.0.6 h1:h8q5ORH/GaOE1Se1DMhrOyljXZEhRcROO7agMqWXCOY= github.com/undefinedlabs/go-mpatch v1.0.6/go.mod h1:TyJZDQ/5AgyN7FSLiBJ8RO9u2c6wbtRvK827b6AVqY4= +github.com/undefinedlabs/go-mpatch v1.0.7 h1:943FMskd9oqfbZV0qRVKOUsXQhTLXL0bQTVbQSpzmBs= +github.com/undefinedlabs/go-mpatch v1.0.7/go.mod h1:TyJZDQ/5AgyN7FSLiBJ8RO9u2c6wbtRvK827b6AVqY4= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E= @@ -352,8 +363,8 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= -go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= @@ -381,8 +392,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -467,8 +478,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -517,10 +528,12 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= +golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= +golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/pkg/document/crdt/array.go b/pkg/document/crdt/array.go index 1a5dcd7a3..f0dcb07db 100644 --- a/pkg/document/crdt/array.go +++ b/pkg/document/crdt/array.go @@ -178,6 +178,18 @@ func (a *Array) DeleteByCreatedAt(createdAt *time.Ticket, deletedAt *time.Ticket return node.elem, nil } +// Set sets the given element at the given position of the creation time. +func (a *Array) Set(createdAt *time.Ticket, element Element, executedAt *time.Ticket) (Element, error) { + node, err := a.elements.Set(createdAt, element, executedAt) + if err != nil { + return nil, err + } + if node != nil { + return node.elem, nil + } + return nil, nil +} + // Len returns length of this Array. func (a *Array) Len() int { return a.elements.Len() diff --git a/pkg/document/crdt/rga_tree_list.go b/pkg/document/crdt/rga_tree_list.go index c2e71baac..eae582817 100644 --- a/pkg/document/crdt/rga_tree_list.go +++ b/pkg/document/crdt/rga_tree_list.go @@ -345,3 +345,27 @@ func (a *RGATreeList) insertAfter( a.nodeMapByCreatedAt[value.CreatedAt().Key()] = newNode return nil } + +// Set sets the given element at the given creation time. +func (a *RGATreeList) Set( + createdAt *time.Ticket, + element Element, + executedAt *time.Ticket, +) (*RGATreeListNode, error) { + node, ok := a.nodeMapByCreatedAt[createdAt.Key()] + if !ok { + return nil, fmt.Errorf("set %s: %w", createdAt.Key(), ErrChildNotFound) + } + + var removed *RGATreeListNode + // TODO(junseo): Replace `MovedAt()` with `UpdatedAt()` + // because `movedAt` is related to convergence of positional operations (Insert, Move). + // In the current implementation, concurrent Set and Insert operations do not converge. + if node.elem.MovedAt() == nil || executedAt.After(node.elem.MovedAt()) { + removed = newRGATreeListNode(node.elem) + + node.elem = element + node.elem.SetMovedAt(executedAt) + } + return removed, nil +} diff --git a/pkg/document/json/array.go b/pkg/document/json/array.go index 954615ea6..8b024e706 100644 --- a/pkg/document/json/array.go +++ b/pkg/document/json/array.go @@ -167,10 +167,24 @@ func (p *Array) MoveBefore(nextCreatedAt, createdAt *time.Ticket) { p.moveBeforeInternal(nextCreatedAt, createdAt) } +// MoveAfterByIndex moves the given element to its new position after the given previous element. +func (p *Array) MoveAfterByIndex(prevIndex, targetIndex int) { + prev := p.Get(prevIndex) + target := p.Get(targetIndex) + if prev == nil || target == nil { + panic("index out of bound") + } + p.moveAfterInternal(prev.CreatedAt(), target.CreatedAt()) +} + // InsertIntegerAfter inserts the given integer after the given previous // element. func (p *Array) InsertIntegerAfter(index int, v int) *Array { - p.insertAfterInternal(p.Get(index).CreatedAt(), func(ticket *time.Ticket) crdt.Element { + prev := p.Get(index) + if prev == nil { + panic("index out of bound") + } + p.insertAfterInternal(prev.CreatedAt(), func(ticket *time.Ticket) crdt.Element { primitive, err := crdt.NewPrimitive(v, ticket) if err != nil { panic(err) @@ -183,7 +197,7 @@ func (p *Array) InsertIntegerAfter(index int, v int) *Array { // Get element of the given index. func (p *Array) Get(idx int) crdt.Element { - if p.Len() <= idx { + if idx < 0 || p.Len() <= idx { return nil } @@ -197,15 +211,11 @@ func (p *Array) Get(idx int) crdt.Element { // GetObject returns Object of the given index. func (p *Array) GetObject(idx int) *Object { - if p.Len() <= idx { + element := p.Get(idx) + if element == nil { return nil } - element, err := p.Array.Get(idx) - if err != nil { - panic(err) - } - switch elem := element.(type) { case *crdt.Object: return NewObject(p.context, elem) @@ -218,15 +228,11 @@ func (p *Array) GetObject(idx int) *Object { // GetArray returns Array of the given index. func (p *Array) GetArray(idx int) *Array { - if p.Len() <= idx { + element := p.Get(idx) + if element == nil { return nil } - element, err := p.Array.Get(idx) - if err != nil { - panic(err) - } - switch elem := element.(type) { case *crdt.Array: return NewArray(p.context, elem) @@ -239,15 +245,11 @@ func (p *Array) GetArray(idx int) *Array { // GetText returns Text of the given index. func (p *Array) GetText(idx int) *Text { - if p.Len() <= idx { + element := p.Get(idx) + if element == nil { return nil } - element, err := p.Array.Get(idx) - if err != nil { - panic(err) - } - switch elem := element.(type) { case *crdt.Text: text := NewText() @@ -261,15 +263,11 @@ func (p *Array) GetText(idx int) *Text { // GetCounter returns Counter of the given index. func (p *Array) GetCounter(idx int) *Counter { - if p.Len() <= idx { + element := p.Get(idx) + if element == nil { return nil } - element, err := p.Array.Get(idx) - if err != nil { - panic(err) - } - switch elem := element.(type) { case *crdt.Counter: counter := NewCounter(elem.Value(), elem.ValueType()) @@ -283,15 +281,11 @@ func (p *Array) GetCounter(idx int) *Counter { // GetTree returns Tree of the given index. func (p *Array) GetTree(idx int) *Tree { - if p.Len() <= idx { + element := p.Get(idx) + if element == nil { return nil } - element, err := p.Array.Get(idx) - if err != nil { - panic(err) - } - switch elem := element.(type) { case *crdt.Tree: tree := NewTree() @@ -303,9 +297,26 @@ func (p *Array) GetTree(idx int) *Tree { } } +// SetInteger sets element of the given index. +func (p *Array) SetInteger(idx int, value int) *Array { + target := p.Get(idx) + if target == nil { + panic("index out of bound") + } + + p.setByIndexInternal(target.CreatedAt(), func(ticket *time.Ticket) crdt.Element { + primitive, err := crdt.NewPrimitive(value, ticket) + if err != nil { + panic(err) + } + return primitive + }) + return p +} + // Delete deletes the element of the given index. func (p *Array) Delete(idx int) crdt.Element { - if p.Len() <= idx { + if idx < 0 || p.Len() <= idx { return nil } @@ -381,6 +392,52 @@ func (p *Array) moveBeforeInternal(nextCreatedAt, createdAt *time.Ticket) { } } +func (p *Array) moveAfterInternal(prevCreatedAt, createdAt *time.Ticket) { + ticket := p.context.IssueTimeTicket() + + p.context.Push(operations.NewMove( + p.Array.CreatedAt(), + prevCreatedAt, + createdAt, + ticket, + )) + + if err := p.MoveAfter(prevCreatedAt, createdAt, ticket); err != nil { + panic(err) + } +} + +func (p *Array) setByIndexInternal( + createdAt *time.Ticket, + creator func(ticket *time.Ticket) crdt.Element, +) crdt.Element { + ticket := p.context.IssueTimeTicket() + // NOTE(junseo): It uses `creator(createdAt)` instead of `creator(ticket)` + // because the new element must have the same `createdAt` as the old element. + elem := creator(createdAt) + value := toOriginal(elem) + + copiedValue, err := value.DeepCopy() + if err != nil { + panic(err) + } + p.context.Push(operations.NewArraySet( + p.Array.CreatedAt(), + createdAt, + copiedValue, + ticket, + )) + + _, err = p.Set(createdAt, value, ticket) + if err != nil { + panic(err) + } + // TODO(junseo): GC logic is not implemented here + // because there is no way to distinguish between old and new element with same `createdAt`. + p.context.RegisterElement(value) + return elem +} + // buildArrayElements return the element slice of the given array. // Because the type of the given array is `any`, it is necessary to type assertion. func buildArrayElements( diff --git a/pkg/document/json/object.go b/pkg/document/json/object.go index de31d8da4..24398abd9 100644 --- a/pkg/document/json/object.go +++ b/pkg/document/json/object.go @@ -43,6 +43,13 @@ func NewObject(ctx *change.Context, root *crdt.Object) *Object { } } +// SetDynamicValue sets a dynamic value for the given key. +func (p *Object) SetDynamicValue(k string, v any) { + p.setInternal(k, func(ticket *time.Ticket) crdt.Element { + return toElement(p.context, buildCRDTElement(p.context, v, ticket, newBuildState())) + }) +} + // SetNewObject sets a new Object for the given key. func (p *Object) SetNewObject(k string, v ...any) *Object { value := p.setInternal(k, func(ticket *time.Ticket) crdt.Element { diff --git a/pkg/document/operations/array_set.go b/pkg/document/operations/array_set.go new file mode 100644 index 000000000..11842a435 --- /dev/null +++ b/pkg/document/operations/array_set.go @@ -0,0 +1,102 @@ +/* + * Copyright 2024 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 operations + +import ( + "github.com/yorkie-team/yorkie/pkg/document/crdt" + "github.com/yorkie-team/yorkie/pkg/document/time" +) + +// ArraySet is an operation representing setting an element in Array. +type ArraySet struct { + // parentCreatedAt is the creation time of the Array that executes ArraySet. + parentCreatedAt *time.Ticket + + // createdAt is the creation time of the target element to set. + createdAt *time.Ticket + + // value is an element set by the set_by_index operations. + value crdt.Element + + // executedAt is the time the operation was executed. + executedAt *time.Ticket +} + +// NewArraySet creates a new instance of ArraySet. +func NewArraySet( + parentCreatedAt *time.Ticket, + createdAt *time.Ticket, + value crdt.Element, + executedAt *time.Ticket, +) *ArraySet { + return &ArraySet{ + parentCreatedAt: parentCreatedAt, + createdAt: createdAt, + value: value, + executedAt: executedAt, + } +} + +// Execute executes this operation on the given document(`root`). +func (o *ArraySet) Execute(root *crdt.Root) error { + parent := root.FindByCreatedAt(o.parentCreatedAt) + + obj, ok := parent.(*crdt.Array) + if !ok { + return ErrNotApplicableDataType + } + + value, err := o.value.DeepCopy() + if err != nil { + return err + } + + _, err = obj.Set(o.createdAt, value, o.executedAt) + if err != nil { + return err + } + + // TODO(junseo): GC logic is not implemented here + // because there is no way to distinguish between old and new element with same `createdAt`. + root.RegisterElement(value) + return nil +} + +// Value returns the value of this operation. +func (o *ArraySet) Value() crdt.Element { + return o.value +} + +// ParentCreatedAt returns the creation time of the Array. +func (o *ArraySet) ParentCreatedAt() *time.Ticket { + return o.parentCreatedAt +} + +// ExecutedAt returns execution time of this operation. +func (o *ArraySet) ExecutedAt() *time.Ticket { + return o.executedAt +} + +// SetActor sets the given actor to this operation. +func (o *ArraySet) SetActor(actorID *time.ActorID) { + o.executedAt = o.executedAt.SetActorID(actorID) +} + +// CreatedAt returns the creation time of the target element. +func (o *ArraySet) CreatedAt() *time.Ticket { + return o.createdAt +} diff --git a/server/backend/backend.go b/server/backend/backend.go index b007c3207..de4052829 100644 --- a/server/backend/backend.go +++ b/server/backend/backend.go @@ -43,16 +43,15 @@ import ( // Backend manages Yorkie's backend such as Database and Coordinator. And it // has the server status such as the information of this Server. type Backend struct { - Config *Config - serverInfo *sync.ServerInfo + Config *Config + serverInfo *sync.ServerInfo + AuthWebhookCache *cache.LRUExpireCache[string, *types.AuthWebhookResponse] + Metrics *prometheus.Metrics DB database.Database Coordinator sync.Coordinator - Metrics *prometheus.Metrics Background *background.Background Housekeeping *housekeeping.Housekeeping - - AuthWebhookCache *cache.LRUExpireCache[string, *types.AuthWebhookResponse] } // New creates a new instance of Backend. @@ -62,6 +61,8 @@ func New( housekeepingConf *housekeeping.Config, metrics *prometheus.Metrics, ) (*Backend, error) { + // 01. Build the server info with the given hostname or the hostname of the + // current machine. hostname := conf.Hostname if hostname == "" { hostname, err := os.Hostname() @@ -77,10 +78,21 @@ func New( UpdatedAt: time.Now(), } - bg := background.New() + // 02. Create the auth webhook cache. The auth webhook cache is used to + // cache the response of the auth webhook. + // TODO(hackerwins): Consider to extend the cache for general purpose. + webhookCache, err := cache.NewLRUExpireCache[string, *types.AuthWebhookResponse](conf.AuthWebhookCacheSize) + if err != nil { + return nil, err + } + + // 03. Create the background instance. The background instance is used to + // manage background tasks. + bg := background.New(metrics) + // 04. Create the database instance. If the MongoDB configuration is given, + // create a MongoDB instance. Otherwise, create a memory database instance. var db database.Database - var err error if mongoConf != nil { db, err = mongo.Dial(mongoConf) if err != nil { @@ -93,23 +105,32 @@ func New( } } + // 05. Create the coordinator instance. The coordinator is used to manage + // the synchronization between the Yorkie servers. // TODO(hackerwins): Implement the coordinator for a shard. For now, we // distribute workloads to all shards per document. In the future, we // will need to distribute workloads of a document. coordinator := memsync.NewCoordinator(serverInfo) - authWebhookCache, err := cache.NewLRUExpireCache[string, *types.AuthWebhookResponse](conf.AuthWebhookCacheSize) + // 06. Create the housekeeping instance. The housekeeping is used + // to manage keeping tasks such as deactivating inactive clients. + keeping, err := housekeeping.New(housekeepingConf) if err != nil { return nil, err } - keeping, err := housekeeping.Start( - housekeepingConf, - db, - coordinator, - ) - if err != nil { - return nil, err + // 07. Ensure the default user and project. If the default user and project + // do not exist, create them. + if conf.UseDefaultProject { + _, _, err = db.EnsureDefaultUserAndProject( + context.Background(), + conf.AdminUser, + conf.AdminPassword, + conf.ClientDeactivateThreshold, + ) + if err != nil { + return nil, err + } } dbInfo := "memory" @@ -123,38 +144,37 @@ func New( dbInfo, ) - _, _, err = db.EnsureDefaultUserAndProject( - context.Background(), - conf.AdminUser, - conf.AdminPassword, - conf.ClientDeactivateThreshold, - ) - if err != nil { - return nil, err - } - return &Backend{ - Config: conf, - serverInfo: serverInfo, + Config: conf, + serverInfo: serverInfo, + AuthWebhookCache: webhookCache, - Background: bg, Metrics: metrics, DB: db, Coordinator: coordinator, + Background: bg, Housekeeping: keeping, - - AuthWebhookCache: authWebhookCache, }, nil } +// Start starts the backend. +func (b *Backend) Start() error { + if err := b.Housekeeping.Start(); err != nil { + return err + } + + logging.DefaultLogger().Infof("backend started: id: %s", b.serverInfo.ID) + return nil +} + // Shutdown closes all resources of this instance. func (b *Backend) Shutdown() error { - b.Background.Close() - if err := b.Housekeeping.Stop(); err != nil { return err } + b.Background.Close() + if err := b.Coordinator.Close(); err != nil { logging.DefaultLogger().Error(err) } diff --git a/server/backend/background/background.go b/server/backend/background/background.go index 7216d2c52..677010350 100644 --- a/server/backend/background/background.go +++ b/server/backend/background/background.go @@ -25,6 +25,7 @@ import ( "sync/atomic" "github.com/yorkie-team/yorkie/server/logging" + "github.com/yorkie-team/yorkie/server/profiling/prometheus" ) type routineID int32 @@ -49,18 +50,25 @@ type Background struct { // routineID is used to generate routine ID. routineID routineID + + // metrics is used to collect metrics with prometheus. + metrics *prometheus.Metrics } // New creates a new background service. -func New() *Background { +func New(metrics *prometheus.Metrics) *Background { return &Background{ closing: make(chan struct{}), + metrics: metrics, } } // AttachGoroutine creates a goroutine on a given function and tracks it using // the background's WaitGroup. -func (b *Background) AttachGoroutine(f func(ctx context.Context)) { +func (b *Background) AttachGoroutine( + f func(ctx context.Context), + taskType string, +) { b.wgMu.RLock() // this blocks with ongoing close(b.closing) defer b.wgMu.RUnlock() select { @@ -73,8 +81,12 @@ func (b *Background) AttachGoroutine(f func(ctx context.Context)) { // now safe to add since WaitGroup wait has not started yet b.wg.Add(1) routineLogger := logging.New(b.routineID.next()) + b.metrics.AddBackgroundGoroutines(taskType) go func() { - defer b.wg.Done() + defer func() { + b.wg.Done() + b.metrics.RemoveBackgroundGoroutines(taskType) + }() f(logging.With(context.Background(), routineLogger)) }() } diff --git a/server/backend/database/database.go b/server/backend/database/database.go index 83b2e439e..53e8a8dd1 100644 --- a/server/backend/database/database.go +++ b/server/backend/database/database.go @@ -124,6 +124,12 @@ type Database interface { hashedPassword string, ) (*UserInfo, error) + // DeleteUserInfoByName deletes a user by name. + DeleteUserInfoByName(ctx context.Context, username string) error + + // ChangeUserPassword changes to new password for user. + ChangeUserPassword(ctx context.Context, username, hashedNewPassword string) error + // FindUserInfoByID returns a user by the given ID. FindUserInfoByID(ctx context.Context, id types.ID) (*UserInfo, error) @@ -167,6 +173,13 @@ type Database interface { docKey key.Key, ) (*DocInfo, error) + // FindDocInfosByKeys finds the documents of the given keys. + FindDocInfosByKeys( + ctx context.Context, + projectID types.ID, + docKeys []key.Key, + ) ([]*DocInfo, error) + // FindDocInfoByKeyAndOwner finds the document of the given key. If the // createDocIfNotExist condition is true, create the document if it does not // exist. diff --git a/server/backend/database/memory/database.go b/server/backend/database/memory/database.go index 0be96dc82..9b01dd51a 100644 --- a/server/backend/database/memory/database.go +++ b/server/backend/database/memory/database.go @@ -403,6 +403,52 @@ func (d *DB) CreateUserInfo( return info, nil } +// DeleteUserInfoByName deletes a user by name. +func (d *DB) DeleteUserInfoByName(_ context.Context, username string) error { + txn := d.db.Txn(true) + defer txn.Abort() + + raw, err := txn.First(tblUsers, "username", username) + if err != nil { + return fmt.Errorf("find user by username: %w", err) + } + if raw == nil { + return fmt.Errorf("%s: %w", username, database.ErrUserNotFound) + } + + info := raw.(*database.UserInfo).DeepCopy() + if err = txn.Delete(tblUsers, info); err != nil { + return fmt.Errorf("delete account %s: %w", info.ID, err) + } + + txn.Commit() + return nil +} + +// ChangeUserPassword changes to new password. +func (d *DB) ChangeUserPassword(_ context.Context, username, hashedNewPassword string) error { + txn := d.db.Txn(true) + defer txn.Abort() + + raw, err := txn.First(tblUsers, "username", username) + if err != nil { + return fmt.Errorf("find user by username: %w", err) + } + if raw == nil { + return fmt.Errorf("%s: %w", username, database.ErrUserNotFound) + } + + info := raw.(*database.UserInfo).DeepCopy() + info.HashedPassword = hashedNewPassword + if err := txn.Insert(tblUsers, info); err != nil { + return fmt.Errorf("change password user: %w", err) + } + + txn.Commit() + + return nil +} + // FindUserInfoByID finds a user by the given ID. func (d *DB) FindUserInfoByID(_ context.Context, clientID types.ID) (*database.UserInfo, error) { txn := d.db.Txn(false) @@ -701,6 +747,7 @@ func (d *DB) FindDocInfoByKeyAndOwner( Owner: clientRefKey.ClientID, ServerSeq: 0, CreatedAt: now, + UpdatedAt: now, AccessedAt: now, } if err := txn.Insert(tblDocuments, info); err != nil { @@ -757,6 +804,31 @@ func (d *DB) FindDocInfoByKey( return info.DeepCopy(), nil } +// FindDocInfosByKeys finds the documents of the given keys. +func (d *DB) FindDocInfosByKeys( + _ context.Context, + projectID types.ID, + keys []key.Key, +) ([]*database.DocInfo, error) { + txn := d.db.Txn(false) + defer txn.Abort() + + var infos []*database.DocInfo + for _, k := range keys { + info, err := d.findDocInfoByKey(txn, projectID, k) + if err != nil { + return nil, fmt.Errorf("find doc info by key: %w", err) + } + if info == nil { + continue + } + + infos = append(infos, info.DeepCopy()) + } + + return infos, nil +} + // FindDocInfoByRefKey finds a docInfo of the given refKey. func (d *DB) FindDocInfoByRefKey( _ context.Context, @@ -877,7 +949,14 @@ func (d *DB) CreateChangeInfos( now := gotime.Now() loadedDocInfo.ServerSeq = docInfo.ServerSeq - loadedDocInfo.UpdatedAt = now + + for _, cn := range changes { + if len(cn.Operations()) > 0 { + loadedDocInfo.UpdatedAt = now + break + } + } + if isRemoved { loadedDocInfo.RemovedAt = now } @@ -975,6 +1054,9 @@ func (d *DB) FindChangeInfosBetweenServerSeqs( txn := d.db.Txn(false) defer txn.Abort() + if from > to { + return nil, nil + } var infos []*database.ChangeInfo iterator, err := txn.LowerBound( diff --git a/server/backend/database/memory/database_test.go b/server/backend/database/memory/database_test.go index cc36ce8f7..d308940a7 100644 --- a/server/backend/database/memory/database_test.go +++ b/server/backend/database/memory/database_test.go @@ -48,6 +48,10 @@ func TestDB(t *testing.T) { testcases.RunFindDocInfoTest(t, db, projectID) }) + t.Run("RunFindDocInfosByKeys test", func(t *testing.T) { + testcases.RunFindDocInfosByKeysTest(t, db, projectID) + }) + t.Run("RunFindDocInfosByQuery test", func(t *testing.T) { testcases.RunFindDocInfosByQueryTest(t, db, projectOneID) }) @@ -56,6 +60,10 @@ func TestDB(t *testing.T) { testcases.RunFindChangesBetweenServerSeqsTest(t, db, projectID) }) + t.Run("RunFindChangeInfosBetweenServerSeqsTest test", func(t *testing.T) { + testcases.RunFindChangeInfosBetweenServerSeqsTest(t, db, projectID) + }) + t.Run("RunFindClosestSnapshotInfo test", func(t *testing.T) { testcases.RunFindClosestSnapshotInfoTest(t, db, projectID) }) diff --git a/server/backend/database/mongo/client.go b/server/backend/database/mongo/client.go index b3e35540e..f4291fe39 100644 --- a/server/backend/database/mongo/client.go +++ b/server/backend/database/mongo/client.go @@ -429,6 +429,35 @@ func (c *Client) CreateUserInfo( return info, nil } +// DeleteUserInfoByName deletes a user by name. +func (c *Client) DeleteUserInfoByName(ctx context.Context, username string) error { + deleteResult, err := c.collection(ColUsers).DeleteOne(ctx, bson.M{ + "username": username, + }) + if err != nil { + return err + } + if deleteResult.DeletedCount == 0 { + return fmt.Errorf("no user found with username %s", username) + } + return nil +} + +// ChangeUserPassword changes to new password for user. +func (c *Client) ChangeUserPassword(ctx context.Context, username, hashedNewPassword string) error { + updateResult, err := c.collection(ColUsers).UpdateOne(ctx, + bson.M{"username": username}, + bson.M{"$set": bson.M{"hashed_password": hashedNewPassword}}, + ) + if err != nil { + return err + } + if updateResult.ModifiedCount == 0 { + return fmt.Errorf("no user found with username %s", username) + } + return nil +} + // FindUserInfoByID returns a user by ID. func (c *Client) FindUserInfoByID(ctx context.Context, clientID types.ID) (*database.UserInfo, error) { result := c.collection(ColUsers).FindOne(ctx, bson.M{ @@ -710,8 +739,9 @@ func (c *Client) FindDocInfoByKeyAndOwner( "owner": clientRefKey.ClientID, "server_seq": 0, "created_at": now, + "updated_at": now, }, - }) + }, options.FindOneAndUpdate().SetReturnDocument(options.After)) } else { result = c.collection(ColDocuments).FindOne(ctx, filter) if result.Err() == mongo.ErrNoDocuments { @@ -763,6 +793,38 @@ func (c *Client) FindDocInfoByKey( return &docInfo, nil } +// FindDocInfosByKeys finds the documents of the given keys. +func (c *Client) FindDocInfosByKeys( + ctx context.Context, + projectID types.ID, + docKeys []key.Key, +) ([]*database.DocInfo, error) { + if len(docKeys) == 0 { + return nil, nil + } + filter := bson.M{ + "project_id": projectID, + "key": bson.M{ + "$in": docKeys, + }, + "removed_at": bson.M{ + "$exists": false, + }, + } + + cursor, err := c.collection(ColDocuments).Find(ctx, filter) + if err != nil { + return nil, fmt.Errorf("find documents: %w", err) + } + + var docInfos []*database.DocInfo + if err := cursor.All(ctx, &docInfos); err != nil { + return nil, fmt.Errorf("fetch documents: %w", err) + } + + return docInfos, nil +} + // FindDocInfoByRefKey finds a docInfo of the given refKey. func (c *Client) FindDocInfoByRefKey( ctx context.Context, @@ -863,8 +925,15 @@ func (c *Client) CreateChangeInfos( now := gotime.Now() updateFields := bson.M{ "server_seq": docInfo.ServerSeq, - "updated_at": now, } + + for _, cn := range changes { + if len(cn.Operations()) > 0 { + updateFields["updated_at"] = now + break + } + } + if isRemoved { updateFields["removed_at"] = now } @@ -963,6 +1032,9 @@ func (c *Client) FindChangeInfosBetweenServerSeqs( from int64, to int64, ) ([]*database.ChangeInfo, error) { + if from > to { + return nil, nil + } cursor, err := c.collection(ColChanges).Find(ctx, bson.M{ "project_id": docRefKey.ProjectID, "doc_id": docRefKey.DocID, diff --git a/server/backend/database/mongo/client_test.go b/server/backend/database/mongo/client_test.go index f59eca9b3..6e0803b5d 100644 --- a/server/backend/database/mongo/client_test.go +++ b/server/backend/database/mongo/client_test.go @@ -63,6 +63,10 @@ func TestClient(t *testing.T) { testcases.RunFindDocInfoTest(t, cli, dummyProjectID) }) + t.Run("RunFindDocInfosByKeys test", func(t *testing.T) { + testcases.RunFindDocInfosByKeysTest(t, cli, dummyProjectID) + }) + t.Run("RunFindDocInfosByQuery test", func(t *testing.T) { t.Skip("TODO(hackerwins): the order of docInfos is different with memDB") testcases.RunFindDocInfosByQueryTest(t, cli, projectOneID) @@ -72,6 +76,10 @@ func TestClient(t *testing.T) { testcases.RunFindChangesBetweenServerSeqsTest(t, cli, dummyProjectID) }) + t.Run("RunFindChangeInfosBetweenServerSeqsTest test", func(t *testing.T) { + testcases.RunFindChangeInfosBetweenServerSeqsTest(t, cli, dummyProjectID) + }) + t.Run("RunFindClosestSnapshotInfo test", func(t *testing.T) { testcases.RunFindClosestSnapshotInfoTest(t, cli, dummyProjectID) }) diff --git a/server/backend/database/testcases/testcases.go b/server/backend/database/testcases/testcases.go index 379517989..831d18bdb 100644 --- a/server/backend/database/testcases/testcases.go +++ b/server/backend/database/testcases/testcases.go @@ -93,6 +93,92 @@ func RunFindDocInfoTest( }) } +// RunFindDocInfosByKeysTest runs the FindDocInfosByKeys test for the given db. +func RunFindDocInfosByKeysTest( + t *testing.T, + db database.Database, + projectID types.ID, +) { + t.Run("find docInfos by keys test", func(t *testing.T) { + ctx := context.Background() + clientInfo, err := db.ActivateClient(ctx, projectID, t.Name()) + assert.NoError(t, err) + + // 01. Create documents + docKeys := []key.Key{ + "test", "test$3", "test123", "test$0", + "search$test", "abcde", "test abc", + } + for _, docKey := range docKeys { + _, err := db.FindDocInfoByKeyAndOwner(ctx, clientInfo.RefKey(), docKey, true) + assert.NoError(t, err) + } + + // 02. Find documents + infos, err := db.FindDocInfosByKeys(ctx, projectID, docKeys) + assert.NoError(t, err) + + actualKeys := make([]key.Key, len(infos)) + for i, info := range infos { + actualKeys[i] = info.Key + } + + assert.ElementsMatch(t, docKeys, actualKeys) + assert.Len(t, infos, len(docKeys)) + }) + + t.Run("find docInfos by empty key slice test", func(t *testing.T) { + ctx := context.Background() + clientInfo, err := db.ActivateClient(ctx, projectID, t.Name()) + assert.NoError(t, err) + + // 01. Create documents + docKeys := []key.Key{ + "test", "test$3", "test123", "test$0", + "search$test", "abcde", "test abc", + } + for _, docKey := range docKeys { + _, err := db.FindDocInfoByKeyAndOwner(ctx, clientInfo.RefKey(), docKey, true) + assert.NoError(t, err) + } + + // 02. Find documents + infos, err := db.FindDocInfosByKeys(ctx, projectID, nil) + assert.NoError(t, err) + assert.Len(t, infos, 0) + }) + + t.Run("find docInfos by keys where some keys are not found test", func(t *testing.T) { + ctx := context.Background() + clientInfo, err := db.ActivateClient(ctx, projectID, t.Name()) + assert.NoError(t, err) + + // 01. Create documents + docKeys := []key.Key{ + "exist-key1", "exist-key2", "exist-key3", + } + for _, docKey := range docKeys { + _, err := db.FindDocInfoByKeyAndOwner(ctx, clientInfo.RefKey(), docKey, true) + assert.NoError(t, err) + } + + // 02. append a key that does not exist + docKeysWithNonExistKey := append(docKeys, "non-exist-key") + + // 03. Find documents + infos, err := db.FindDocInfosByKeys(ctx, projectID, docKeysWithNonExistKey) + assert.NoError(t, err) + + actualKeys := make([]key.Key, len(infos)) + for i, info := range infos { + actualKeys[i] = info.Key + } + + assert.ElementsMatch(t, docKeys, actualKeys) + assert.Len(t, infos, len(docKeys)) + }) +} + // RunFindProjectInfoBySecretKeyTest runs the FindProjectInfoBySecretKey test for the given db. func RunFindProjectInfoBySecretKeyTest( t *testing.T, @@ -257,6 +343,186 @@ func RunFindChangesBetweenServerSeqsTest( }) } +// RunFindChangeInfosBetweenServerSeqsTest runs the FindChangeInfosBetweenServerSeqs test for the given db. +func RunFindChangeInfosBetweenServerSeqsTest( + t *testing.T, + db database.Database, + projectID types.ID, +) { + t.Run("continues editing without any interference from other users test", func(t *testing.T) { + ctx := context.Background() + + docKey := key.Key(fmt.Sprintf("tests$%s", t.Name())) + + clientInfo, _ := db.ActivateClient(ctx, projectID, t.Name()) + docInfo, _ := db.FindDocInfoByKeyAndOwner(ctx, clientInfo.RefKey(), docKey, true) + assert.NoError(t, clientInfo.AttachDocument(docInfo.ID, false)) + assert.NoError(t, db.UpdateClientInfoAfterPushPull(ctx, clientInfo, docInfo)) + + updatedClientInfo, _ := db.FindClientInfoByRefKey(ctx, clientInfo.RefKey()) + + // Record the serverSeq value at the time the PushPull request came in. + initialServerSeq := docInfo.ServerSeq + + // The serverSeq of the checkpoint that the server has should always be the same as + // the serverSeq of the user's checkpoint that came in as a request, if no other user interfered. + reqPackCheckpointServerSeq := updatedClientInfo.Checkpoint(docInfo.ID).ServerSeq + + changeInfos, err := db.FindChangeInfosBetweenServerSeqs( + ctx, + docInfo.RefKey(), + reqPackCheckpointServerSeq+1, + initialServerSeq, + ) + + assert.NoError(t, err) + assert.Len(t, changeInfos, 0) + }) + + t.Run("retrieving a document with snapshot that reflect the latest doc info test", func(t *testing.T) { + ctx := context.Background() + + docKey := key.Key(fmt.Sprintf("tests$%s", t.Name())) + + clientInfo, _ := db.ActivateClient(ctx, projectID, t.Name()) + docInfo, _ := db.FindDocInfoByKeyAndOwner(ctx, clientInfo.RefKey(), docKey, true) + docRefKey := docInfo.RefKey() + assert.NoError(t, clientInfo.AttachDocument(docInfo.ID, false)) + assert.NoError(t, db.UpdateClientInfoAfterPushPull(ctx, clientInfo, docInfo)) + + initialServerSeq := docInfo.ServerSeq + + // 01. Create a document and store changes + bytesID, _ := clientInfo.ID.Bytes() + actorID, _ := time.ActorIDFromBytes(bytesID) + doc := document.New(key.Key(t.Name())) + doc.SetActor(actorID) + assert.NoError(t, doc.Update(func(root *json.Object, p *presence.Presence) error { + root.SetNewArray("array") + return nil + })) + for idx := 0; idx < 5; idx++ { + assert.NoError(t, doc.Update(func(root *json.Object, p *presence.Presence) error { + root.GetArray("array").AddInteger(idx) + return nil + })) + } + + pack := doc.CreateChangePack() + for _, c := range pack.Changes { + serverSeq := docInfo.IncreaseServerSeq() + c.SetServerSeq(serverSeq) + } + + err := db.CreateChangeInfos( + ctx, + projectID, + docInfo, + initialServerSeq, + pack.Changes, + false, + ) + assert.NoError(t, err) + + // 02. Create a snapshot that reflect the latest doc info + updatedDocInfo, _ := db.FindDocInfoByRefKey(ctx, docRefKey) + assert.Equal(t, int64(6), updatedDocInfo.ServerSeq) + + pack = change.NewPack( + updatedDocInfo.Key, + change.InitialCheckpoint.NextServerSeq(updatedDocInfo.ServerSeq), + nil, + doc.VersionVector(), + nil, + ) + assert.NoError(t, doc.ApplyChangePack(pack)) + assert.Equal(t, int64(6), doc.Checkpoint().ServerSeq) + + assert.NoError(t, db.CreateSnapshotInfo(ctx, docRefKey, doc.InternalDocument())) + + // 03. Find changeInfos with snapshot that reflect the latest doc info + snapshotInfo, _ := db.FindClosestSnapshotInfo( + ctx, + docRefKey, + updatedDocInfo.ServerSeq, + false, + ) + + changeInfos, _ := db.FindChangeInfosBetweenServerSeqs( + ctx, + docRefKey, + snapshotInfo.ServerSeq+1, + updatedDocInfo.ServerSeq, + ) + + assert.Len(t, changeInfos, 0) + }) + + t.Run("store changes and find changes test", func(t *testing.T) { + ctx := context.Background() + + docKey := key.Key(fmt.Sprintf("tests$%s", t.Name())) + + clientInfo, _ := db.ActivateClient(ctx, projectID, t.Name()) + docInfo, _ := db.FindDocInfoByKeyAndOwner(ctx, clientInfo.RefKey(), docKey, true) + docRefKey := docInfo.RefKey() + assert.NoError(t, clientInfo.AttachDocument(docInfo.ID, false)) + assert.NoError(t, db.UpdateClientInfoAfterPushPull(ctx, clientInfo, docInfo)) + + initialServerSeq := docInfo.ServerSeq + + // 01. Create a document and store changes + bytesID, _ := clientInfo.ID.Bytes() + actorID, _ := time.ActorIDFromBytes(bytesID) + doc := document.New(key.Key(t.Name())) + doc.SetActor(actorID) + assert.NoError(t, doc.Update(func(root *json.Object, p *presence.Presence) error { + root.SetNewArray("array") + return nil + })) + for idx := 0; idx < 5; idx++ { + assert.NoError(t, doc.Update(func(root *json.Object, p *presence.Presence) error { + root.GetArray("array").AddInteger(idx) + return nil + })) + } + pack := doc.CreateChangePack() + for _, c := range pack.Changes { + serverSeq := docInfo.IncreaseServerSeq() + c.SetServerSeq(serverSeq) + } + + err := db.CreateChangeInfos( + ctx, + projectID, + docInfo, + initialServerSeq, + pack.Changes, + false, + ) + assert.NoError(t, err) + + // 02. Find changes + changeInfos, err := db.FindChangeInfosBetweenServerSeqs( + ctx, + docRefKey, + 1, + 6, + ) + assert.NoError(t, err) + assert.Len(t, changeInfos, 6) + + changeInfos, err = db.FindChangeInfosBetweenServerSeqs( + ctx, + docRefKey, + 3, + 3, + ) + assert.NoError(t, err) + assert.Len(t, changeInfos, 1) + }) +} + // RunFindClosestSnapshotInfoTest runs the FindClosestSnapshotInfo test for the given db. func RunFindClosestSnapshotInfoTest(t *testing.T, db database.Database, projectID types.ID) { t.Run("store and find snapshots test", func(t *testing.T) { @@ -854,6 +1120,49 @@ func RunCreateChangeInfosTest(t *testing.T, db database.Database, projectID type assert.NoError(t, err) assert.NotEqual(t, database.DocumentRemoved, clientInfo.Documents[docInfo.ID].Status) }) + + t.Run("set updated_at in docInfo test", func(t *testing.T) { + ctx := context.Background() + docKey := helper.TestDocKey(t) + + // 01. Create a client and a document then attach the document to the client. + clientInfo, _ := db.ActivateClient(ctx, projectID, t.Name()) + docInfo1, _ := db.FindDocInfoByKeyAndOwner(ctx, clientInfo.RefKey(), docKey, true) + assert.Equal(t, docInfo1.Owner, clientInfo.ID) + assert.NotEqual(t, gotime.Date(1, gotime.January, 1, 0, 0, 0, 0, gotime.UTC), docInfo1.UpdatedAt) + assert.Equal(t, docInfo1.CreatedAt, docInfo1.UpdatedAt) + docRefKey := docInfo1.RefKey() + assert.NoError(t, clientInfo.AttachDocument(docRefKey.DocID, false)) + assert.NoError(t, db.UpdateClientInfoAfterPushPull(ctx, clientInfo, docInfo1)) + + bytesID, _ := clientInfo.ID.Bytes() + actorID, _ := time.ActorIDFromBytes(bytesID) + doc := document.New(key.Key(t.Name())) + doc.SetActor(actorID) + + // 02. Update document only presence + assert.NoError(t, doc.Update(func(root *json.Object, p *presence.Presence) error { + p.Set("key", "val") + return nil + })) + pack := doc.CreateChangePack() + updatedAt := docInfo1.UpdatedAt + assert.NoError(t, db.CreateChangeInfos(ctx, projectID, docInfo1, 0, pack.Changes, false)) + docInfo2, _ := db.FindDocInfoByKeyAndOwner(ctx, clientInfo.RefKey(), docKey, true) + assert.Equal(t, updatedAt, docInfo2.UpdatedAt) + + // 03. Update document presence and operation + assert.NoError(t, doc.Update(func(root *json.Object, p *presence.Presence) error { + p.Set("key", "val") + root.SetNewArray("array") + return nil + })) + pack = doc.CreateChangePack() + updatedAt = docInfo2.UpdatedAt + assert.NoError(t, db.CreateChangeInfos(ctx, projectID, docInfo2, 0, pack.Changes, false)) + docInfo3, _ := db.FindDocInfoByKeyAndOwner(ctx, clientInfo.RefKey(), docKey, true) + assert.NotEqual(t, updatedAt, docInfo3.UpdatedAt) + }) } // RunUpdateClientInfoAfterPushPullTest runs the UpdateClientInfoAfterPushPull tests for the given db. diff --git a/server/backend/housekeeping/config.go b/server/backend/housekeeping/config.go index 513bbd7a5..ff2902e9f 100644 --- a/server/backend/housekeeping/config.go +++ b/server/backend/housekeeping/config.go @@ -14,6 +14,8 @@ * limitations under the License. */ +// Package housekeeping is the package for housekeeping service. It cleans up +// the resources and data that is no longer needed. package housekeeping import ( @@ -59,3 +61,13 @@ func (c *Config) Validate() error { return nil } + +// ParseInterval parses the interval. +func (c *Config) ParseInterval() (time.Duration, error) { + interval, err := time.ParseDuration(c.Interval) + if err != nil { + return 0, fmt.Errorf("parse interval %s: %w", c.Interval, err) + } + + return interval, nil +} diff --git a/server/backend/housekeeping/housekeeping.go b/server/backend/housekeeping/housekeeping.go index 65c26f5fd..2f54281d3 100644 --- a/server/backend/housekeeping/housekeeping.go +++ b/server/backend/housekeeping/housekeeping.go @@ -14,9 +14,6 @@ * limitations under the License. */ -// Package housekeeping provides the housekeeping service. The housekeeping -// service is responsible for deactivating clients that have not been used for -// a long time. package housekeeping import ( @@ -24,193 +21,67 @@ import ( "fmt" "time" - "github.com/yorkie-team/yorkie/api/types" - "github.com/yorkie-team/yorkie/server/backend/database" - "github.com/yorkie-team/yorkie/server/backend/sync" - "github.com/yorkie-team/yorkie/server/clients" - "github.com/yorkie-team/yorkie/server/logging" -) + "github.com/go-co-op/gocron/v2" -const ( - deactivateCandidatesKey = "housekeeping/deactivateCandidates" + "github.com/yorkie-team/yorkie/server/logging" ) // Housekeeping is the housekeeping service. It periodically runs housekeeping -// tasks. It is responsible for deactivating clients that have not been active -// for a long time. +// tasks. type Housekeeping struct { - database database.Database - coordinator sync.Coordinator - - interval time.Duration - candidatesLimitPerProject int - projectFetchSize int - - ctx context.Context - cancelFunc context.CancelFunc -} + Config *Config -// Start starts the housekeeping service. -func Start( - conf *Config, - database database.Database, - coordinator sync.Coordinator, -) (*Housekeeping, error) { - h, err := New(conf, database, coordinator) - if err != nil { - return nil, err - } - if err := h.Start(); err != nil { - return nil, err - } - - return h, nil + scheduler gocron.Scheduler } // New creates a new housekeeping instance. -func New( - conf *Config, - database database.Database, - coordinator sync.Coordinator, -) (*Housekeeping, error) { - interval, err := time.ParseDuration(conf.Interval) +func New(conf *Config) (*Housekeeping, error) { + scheduler, err := gocron.NewScheduler() if err != nil { - return nil, fmt.Errorf("parse interval %s: %w", conf.Interval, err) + return nil, fmt.Errorf("new scheduler: %w", err) } - ctx, cancelFunc := context.WithCancel(context.Background()) - return &Housekeeping{ - database: database, - coordinator: coordinator, + Config: conf, + scheduler: scheduler, + }, nil +} - interval: interval, - candidatesLimitPerProject: conf.CandidatesLimitPerProject, - projectFetchSize: conf.ProjectFetchSize, +// RegisterTask registers task the housekeeping service. +func (h *Housekeeping) RegisterTask( + interval time.Duration, + task func(ctx context.Context) error, +) error { + if _, err := h.scheduler.NewJob( + gocron.DurationJob(interval), + gocron.NewTask(func() { + ctx := context.Background() + if err := task(ctx); err != nil { + logging.From(ctx).Error(err) + } + }), + ); err != nil { + return fmt.Errorf("scheduler new job: %w", err) + } - ctx: ctx, - cancelFunc: cancelFunc, - }, nil + return nil } // Start starts the housekeeping service. func (h *Housekeeping) Start() error { - go h.run() + h.scheduler.Start() return nil } // Stop stops the housekeeping service. func (h *Housekeeping) Stop() error { - h.cancelFunc() - - return nil -} - -// run is the housekeeping loop. -func (h *Housekeeping) run() { - housekeepingLastProjectID := database.DefaultProjectID - - for { - ctx := context.Background() - lastProjectID, err := h.deactivateCandidates(ctx, housekeepingLastProjectID) - if err != nil { - logging.From(ctx).Error(err) - continue - } - housekeepingLastProjectID = lastProjectID - - select { - case <-time.After(h.interval): - case <-h.ctx.Done(): - return - } + if err := h.scheduler.StopJobs(); err != nil { + return fmt.Errorf("scheduler stop jobs: %w", err) } -} -// deactivateCandidates deactivates candidates. -func (h *Housekeeping) deactivateCandidates( - ctx context.Context, - housekeepingLastProjectID types.ID, -) (types.ID, error) { - start := time.Now() - locker, err := h.coordinator.NewLocker(ctx, deactivateCandidatesKey) - if err != nil { - return database.DefaultProjectID, err - } - - if err := locker.Lock(ctx); err != nil { - return database.DefaultProjectID, err - } - - defer func() { - if err := locker.Unlock(ctx); err != nil { - logging.From(ctx).Error(err) - } - }() - - lastProjectID, candidates, err := h.FindDeactivateCandidates( - ctx, - h.candidatesLimitPerProject, - h.projectFetchSize, - housekeepingLastProjectID, - ) - if err != nil { - return database.DefaultProjectID, err - } - - deactivatedCount := 0 - for _, clientInfo := range candidates { - if _, err := clients.Deactivate( - ctx, - h.database, - clientInfo.RefKey(), - ); err != nil { - return database.DefaultProjectID, err - } - - deactivatedCount++ - } - - if len(candidates) > 0 { - logging.From(ctx).Infof( - "HSKP: candidates %d, deactivated %d, %s", - len(candidates), - deactivatedCount, - time.Since(start), - ) + if err := h.scheduler.Shutdown(); err != nil { + return fmt.Errorf("scheduler shutdown: %w", err) } - return lastProjectID, nil -} - -// FindDeactivateCandidates finds the housekeeping candidates. -func (h *Housekeeping) FindDeactivateCandidates( - ctx context.Context, - candidatesLimitPerProject int, - projectFetchSize int, - lastProjectID types.ID, -) (types.ID, []*database.ClientInfo, error) { - projects, err := h.database.FindNextNCyclingProjectInfos(ctx, projectFetchSize, lastProjectID) - if err != nil { - return database.DefaultProjectID, nil, err - } - - var candidates []*database.ClientInfo - for _, project := range projects { - infos, err := h.database.FindDeactivateCandidatesPerProject(ctx, project, candidatesLimitPerProject) - if err != nil { - return database.DefaultProjectID, nil, err - } - - candidates = append(candidates, infos...) - } - - var topProjectID types.ID - if len(projects) < projectFetchSize { - topProjectID = database.DefaultProjectID - } else { - topProjectID = projects[len(projects)-1].ID - } - - return topProjectID, candidates, nil + return nil } diff --git a/server/clients/housekeeping.go b/server/clients/housekeeping.go new file mode 100644 index 000000000..76ab28bd8 --- /dev/null +++ b/server/clients/housekeeping.go @@ -0,0 +1,122 @@ +/* + * Copyright 2024 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 clients + +import ( + "context" + "time" + + "github.com/yorkie-team/yorkie/api/types" + "github.com/yorkie-team/yorkie/server/backend" + "github.com/yorkie-team/yorkie/server/backend/database" + "github.com/yorkie-team/yorkie/server/logging" +) + +const ( + deactivateCandidatesKey = "housekeeping/deactivateCandidates" +) + +// DeactivateInactives deactivates clients that have not been active for a +// long time. +func DeactivateInactives( + ctx context.Context, + be *backend.Backend, + candidatesLimitPerProject int, + projectFetchSize int, + housekeepingLastProjectID types.ID, +) (types.ID, error) { + start := time.Now() + + locker, err := be.Coordinator.NewLocker(ctx, deactivateCandidatesKey) + if err != nil { + return database.DefaultProjectID, err + } + + if err := locker.Lock(ctx); err != nil { + return database.DefaultProjectID, err + } + + defer func() { + if err := locker.Unlock(ctx); err != nil { + logging.From(ctx).Error(err) + } + }() + + lastProjectID, candidates, err := FindDeactivateCandidates( + ctx, + be, + candidatesLimitPerProject, + projectFetchSize, + housekeepingLastProjectID, + ) + if err != nil { + return database.DefaultProjectID, err + } + + deactivatedCount := 0 + for _, clientInfo := range candidates { + if _, err := Deactivate(ctx, be.DB, clientInfo.RefKey()); err != nil { + return database.DefaultProjectID, err + } + + deactivatedCount++ + } + + if len(candidates) > 0 { + logging.From(ctx).Infof( + "HSKP: candidates %d, deactivated %d, %s", + len(candidates), + deactivatedCount, + time.Since(start), + ) + } + + return lastProjectID, nil +} + +// FindDeactivateCandidates finds candidates to deactivate from the database. +func FindDeactivateCandidates( + ctx context.Context, + be *backend.Backend, + candidatesLimitPerProject int, + projectFetchSize int, + lastProjectID types.ID, +) (types.ID, []*database.ClientInfo, error) { + projects, err := be.DB.FindNextNCyclingProjectInfos(ctx, projectFetchSize, lastProjectID) + if err != nil { + return database.DefaultProjectID, nil, err + } + + var candidates []*database.ClientInfo + for _, project := range projects { + infos, err := be.DB.FindDeactivateCandidatesPerProject(ctx, project, candidatesLimitPerProject) + if err != nil { + return database.DefaultProjectID, nil, err + } + + candidates = append(candidates, infos...) + } + + var topProjectID types.ID + if len(projects) < projectFetchSize { + topProjectID = database.DefaultProjectID + } else { + topProjectID = projects[len(projects)-1].ID + } + + return topProjectID, candidates, nil +} diff --git a/server/documents/documents.go b/server/documents/documents.go index 3a1165155..e73167e34 100644 --- a/server/documents/documents.go +++ b/server/documents/documents.go @@ -97,16 +97,7 @@ func GetDocumentSummary( project *types.Project, k key.Key, ) (*types.DocumentSummary, error) { - // TODO(hackerwins): Split FindDocInfoByKeyAndOwner into upsert and find. - docInfo, err := be.DB.FindDocInfoByKeyAndOwner( - ctx, - types.ClientRefKey{ - ProjectID: project.ID, - ClientID: types.IDFromActorID(time.InitialActorID), - }, - k, - false, - ) + docInfo, err := be.DB.FindDocInfoByKey(ctx, project.ID, k) if err != nil { return nil, err } @@ -129,16 +120,36 @@ func GetDocumentSummary( // GetDocumentSummaries returns a list of document summaries. func GetDocumentSummaries( ctx context.Context, - b *backend.Backend, + be *backend.Backend, project *types.Project, keys []key.Key, + includeSnapshot bool, ) ([]*types.DocumentSummary, error) { - // TODO(hackerwins): Resolve the N+1 problem. + docInfos, err := be.DB.FindDocInfosByKeys(ctx, project.ID, keys) + if err != nil { + return nil, err + } + var summaries []*types.DocumentSummary - for _, k := range keys { - summary, err := GetDocumentSummary(ctx, b, project, k) - if err != nil { - return nil, err + for _, docInfo := range docInfos { + snapshot := "" + if includeSnapshot { + // TODO(hackerwins, kokodak): Resolve the N+1 problem. + doc, err := packs.BuildDocumentForServerSeq(ctx, be, docInfo, docInfo.ServerSeq) + if err != nil { + return nil, err + } + + snapshot = doc.Marshal() + } + + summary := &types.DocumentSummary{ + ID: docInfo.ID, + Key: docInfo.Key, + CreatedAt: docInfo.CreatedAt, + AccessedAt: docInfo.AccessedAt, + UpdatedAt: docInfo.UpdatedAt, + Snapshot: snapshot, } summaries = append(summaries, summary) diff --git a/server/packs/packs.go b/server/packs/packs.go index 7477c2da6..a40ef1247 100644 --- a/server/packs/packs.go +++ b/server/packs/packs.go @@ -81,17 +81,18 @@ func PushPull( // 01. push changes: filter out the changes that are already saved in the database. cpAfterPush, pushedChanges := pushChanges(ctx, clientInfo, docInfo, reqPack, initialServerSeq) - be.Metrics.AddPushPullReceivedChanges(reqPack.ChangesLen()) - be.Metrics.AddPushPullReceivedOperations(reqPack.OperationsLen()) + hostname := be.Config.Hostname + be.Metrics.AddPushPullReceivedChanges(hostname, project, reqPack.ChangesLen()) + be.Metrics.AddPushPullReceivedOperations(hostname, project, reqPack.OperationsLen()) // 02. pull pack: pull changes or a snapshot from the database and create a response pack. respPack, err := pullPack(ctx, be, clientInfo, docInfo, reqPack, cpAfterPush, initialServerSeq, opts.Mode) if err != nil { return nil, err } - be.Metrics.AddPushPullSentChanges(respPack.ChangesLen()) - be.Metrics.AddPushPullSentOperations(respPack.OperationsLen()) - be.Metrics.AddPushPullSnapshotBytes(respPack.SnapshotLen()) + be.Metrics.AddPushPullSentChanges(hostname, project, respPack.ChangesLen()) + be.Metrics.AddPushPullSentOperations(hostname, project, respPack.OperationsLen()) + be.Metrics.AddPushPullSnapshotBytes(hostname, project, respPack.SnapshotLen()) // 03. update the client's document and checkpoint. docRefKey := docInfo.RefKey() @@ -220,7 +221,7 @@ func PushPull( be.Metrics.ObservePushPullSnapshotDurationSeconds( gotime.Since(start).Seconds(), ) - }) + }, "pushpull") } return respPack, nil diff --git a/server/packs/packs_test.go b/server/packs/packs_test.go new file mode 100644 index 000000000..42a85b642 --- /dev/null +++ b/server/packs/packs_test.go @@ -0,0 +1,314 @@ +/* + * Copyright 2024 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 packs_test + +import ( + "context" + "encoding/hex" + "errors" + "fmt" + "log" + "net/http" + "os" + "testing" + + "connectrpc.com/connect" + "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/api/yorkie/v1/v1connect" + "github.com/yorkie-team/yorkie/client" + "github.com/yorkie-team/yorkie/pkg/document" + "github.com/yorkie-team/yorkie/pkg/document/time" + "github.com/yorkie-team/yorkie/server/backend" + "github.com/yorkie-team/yorkie/server/backend/database" + "github.com/yorkie-team/yorkie/server/backend/database/mongo" + "github.com/yorkie-team/yorkie/server/backend/housekeeping" + "github.com/yorkie-team/yorkie/server/clients" + "github.com/yorkie-team/yorkie/server/documents" + "github.com/yorkie-team/yorkie/server/packs" + "github.com/yorkie-team/yorkie/server/profiling/prometheus" + "github.com/yorkie-team/yorkie/server/rpc" + "github.com/yorkie-team/yorkie/test/helper" +) + +var ( + // ErrUpdateClientInfoFailed occurs when updating ClientInfo failed + // for testing purposes. + ErrUpdateClientInfoFailed = errors.New("updating clientinfo failed") +) + +var ( + testRPCServer *rpc.Server + testRPCAddr = fmt.Sprintf("localhost:%d", helper.RPCPort) + testClient v1connect.YorkieServiceClient + testBackend *backend.Backend + testMockDB *MockDB +) + +// MockDB represents a mock database for testing purposes +type MockDB struct { + database.Database + mockUpdateClientInfoAfterPushPull func(context.Context, *database.ClientInfo, *database.DocInfo) error +} + +// NewMockDB returns a mock database with a real database +func NewMockDB(database database.Database) *MockDB { + return &MockDB{ + Database: database, + } +} + +func (m *MockDB) UpdateClientInfoAfterPushPull( + ctx context.Context, + clientInfo *database.ClientInfo, + docInfo *database.DocInfo, +) error { + if m.mockUpdateClientInfoAfterPushPull != nil { + return m.mockUpdateClientInfoAfterPushPull(ctx, clientInfo, docInfo) + } + return m.Database.UpdateClientInfoAfterPushPull(ctx, clientInfo, docInfo) +} + +func TestMain(m *testing.M) { + met, err := prometheus.NewMetrics() + if err != nil { + log.Fatal(err) + } + + testBackend, err = backend.New( + &backend.Config{ + AdminUser: helper.AdminUser, + AdminPassword: helper.AdminPassword, + UseDefaultProject: helper.UseDefaultProject, + ClientDeactivateThreshold: helper.ClientDeactivateThreshold, + SnapshotThreshold: helper.SnapshotThreshold, + AuthWebhookCacheSize: helper.AuthWebhookSize, + ProjectInfoCacheSize: helper.ProjectInfoCacheSize, + ProjectInfoCacheTTL: helper.ProjectInfoCacheTTL.String(), + AdminTokenDuration: helper.AdminTokenDuration, + }, &mongo.Config{ + ConnectionURI: helper.MongoConnectionURI, + YorkieDatabase: helper.TestDBName(), + ConnectionTimeout: helper.MongoConnectionTimeout, + PingTimeout: helper.MongoPingTimeout, + }, &housekeeping.Config{ + Interval: helper.HousekeepingInterval.String(), + CandidatesLimitPerProject: helper.HousekeepingCandidatesLimitPerProject, + ProjectFetchSize: helper.HousekeepingProjectFetchSize, + }, met, + ) + if err != nil { + log.Fatal(err) + } + testMockDB = NewMockDB(testBackend.DB) + testBackend.DB = testMockDB + + project, err := testBackend.DB.FindProjectInfoByID( + context.Background(), + database.DefaultProjectID, + ) + if err != nil { + log.Fatal(err) + } + + testRPCServer, err = rpc.NewServer( + &rpc.Config{ + Port: helper.RPCPort, + }, testBackend, + ) + if err != nil { + log.Fatal(err) + } + + if err = testRPCServer.Start(); err != nil { + log.Fatalf("failed rpc listen: %s\n", err) + } + if err = helper.WaitForServerToStart(testRPCAddr); err != nil { + log.Fatal(err) + } + + authInterceptor := client.NewAuthInterceptor(project.PublicKey, "") + + conn := http.DefaultClient + testClient = v1connect.NewYorkieServiceClient( + conn, + "http://"+testRPCAddr, + connect.WithInterceptors(authInterceptor), + ) + + code := m.Run() + + if err := testBackend.Shutdown(); err != nil { + log.Fatal(err) + } + testRPCServer.Shutdown(true) + os.Exit(code) +} + +func triggerErrUpdateClientInfo(on bool) { + if on { + testMockDB.mockUpdateClientInfoAfterPushPull = func( + context.Context, + *database.ClientInfo, + *database.DocInfo, + ) error { + return ErrUpdateClientInfoFailed + } + } else { + testMockDB.mockUpdateClientInfoAfterPushPull = nil + } +} + +func TestPacks(t *testing.T) { + t.Run("cannot detect change duplication due to clientInfo update failure", func(t *testing.T) { + t.Skip("remove this after resolving pushpull consistency problem") + ctx := context.Background() + + projectInfo, err := testBackend.DB.FindProjectInfoByID( + ctx, + database.DefaultProjectID, + ) + assert.NoError(t, err) + project := projectInfo.ToProject() + + triggerErrUpdateClientInfo(false) + + activateResp, err := testClient.ActivateClient( + context.Background(), + connect.NewRequest(&api.ActivateClientRequest{ClientKey: helper.TestDocKey(t).String()})) + assert.NoError(t, err) + + clientID, _ := hex.DecodeString(activateResp.Msg.ClientId) + resPack, err := testClient.AttachDocument( + context.Background(), + connect.NewRequest(&api.AttachDocumentRequest{ + ClientId: activateResp.Msg.ClientId, + ChangePack: &api.ChangePack{ + DocumentKey: helper.TestDocKey(t).String(), + Checkpoint: &api.Checkpoint{ServerSeq: 0, ClientSeq: 1}, + Changes: []*api.Change{ + { + Id: &api.ChangeID{ + ClientSeq: 1, + Lamport: 1, + ActorId: clientID, + }, + }, + }, + }, + }, + )) + assert.NoError(t, err) + + actorID, err := time.ActorIDFromBytes(clientID) + assert.NoError(t, err) + + docID := types.ID(resPack.Msg.DocumentId) + docRefKey := types.DocRefKey{ + ProjectID: project.ID, + DocID: docID, + } + + // 0. Check docInfo.ServerSeq and clientInfo.Checkpoint + docInfo, err := documents.FindDocInfoByRefKey(ctx, testBackend, docRefKey) + assert.NoError(t, err) + assert.Equal(t, int64(1), docInfo.ServerSeq) + + clientInfo, err := clients.FindActiveClientInfo(ctx, testBackend.DB, types.ClientRefKey{ + ProjectID: project.ID, + ClientID: types.IDFromActorID(actorID), + }) + assert.NoError(t, err) + assert.Equal(t, int64(1), clientInfo.Checkpoint(docID).ServerSeq) + assert.Equal(t, uint32(1), clientInfo.Checkpoint(docID).ClientSeq) + + // 1. Create a ChangePack with a single Change + pack, err := converter.FromChangePack(&api.ChangePack{ + DocumentKey: helper.TestDocKey(t).String(), + Checkpoint: &api.Checkpoint{ServerSeq: 0, ClientSeq: 2}, + Changes: []*api.Change{ + { + Id: &api.ChangeID{ + ClientSeq: 2, + Lamport: 2, + ActorId: clientID, + }, + }, + }, + }) + assert.NoError(t, err) + + // 2-1. An arbitrary failure occurs while updating clientInfo + triggerErrUpdateClientInfo(true) + + _, err = packs.PushPull(ctx, testBackend, project, clientInfo, docInfo, pack, packs.PushPullOptions{ + Mode: types.SyncModePushPull, + Status: document.StatusAttached, + }) + assert.ErrorIs(t, err, ErrUpdateClientInfoFailed) + + triggerErrUpdateClientInfo(false) + + // 2-2. pushed change is stored in the database + changes, err := packs.FindChanges(ctx, testBackend, docInfo, 2, 2) + assert.NoError(t, err) + assert.Len(t, changes, 1) + + // 2-3. docInfo.ServerSeq increases from 1 to 2 + docInfo, err = documents.FindDocInfoByRefKey(ctx, testBackend, docRefKey) + assert.NoError(t, err) + assert.Equal(t, int64(2), docInfo.ServerSeq) + + // 2-4. clientInfo.Checkpoint has not been updated + clientInfo, err = clients.FindActiveClientInfo(ctx, testBackend.DB, types.ClientRefKey{ + ProjectID: project.ID, + ClientID: types.IDFromActorID(actorID), + }) + assert.NoError(t, err) + assert.Equal(t, int64(1), clientInfo.Checkpoint(docID).ServerSeq) + assert.Equal(t, uint32(1), clientInfo.Checkpoint(docID).ClientSeq) + + // 3-1. A duplicate request is sent + _, err = packs.PushPull(ctx, testBackend, project, clientInfo, docInfo, pack, packs.PushPullOptions{ + Mode: types.SyncModePushPull, + Status: document.StatusAttached, + }) + assert.NoError(t, err) + + // 3-2. duplicated change is not stored in the database + changes, err = packs.FindChanges(ctx, testBackend, docInfo, 3, 3) + assert.NoError(t, err) + assert.Len(t, changes, 0) + + // 3-3. The server should detect the duplication and not update docInfo.ServerSeq + docInfo, err = documents.FindDocInfoByRefKey(ctx, testBackend, docRefKey) + assert.NoError(t, err) + assert.Equal(t, int64(2), docInfo.ServerSeq) + + // 3-4. clientInfo.Checkpoint has been updated properly + clientInfo, err = clients.FindActiveClientInfo(ctx, testBackend.DB, types.ClientRefKey{ + ProjectID: project.ID, + ClientID: types.IDFromActorID(actorID), + }) + assert.NoError(t, err) + assert.Equal(t, int64(2), clientInfo.Checkpoint(docID).ServerSeq) + assert.Equal(t, uint32(2), clientInfo.Checkpoint(docID).ClientSeq) + }) +} diff --git a/server/profiling/prometheus/metrics.go b/server/profiling/prometheus/metrics.go index 5f3383af2..87740f483 100644 --- a/server/profiling/prometheus/metrics.go +++ b/server/profiling/prometheus/metrics.go @@ -29,13 +29,15 @@ import ( ) const ( - namespace = "yorkie" - sdkTypeLabel = "sdk_type" - sdkVersionLabel = "sdk_version" - methodLabel = "grpc_method" - projectIDLabel = "project_id" - projectNameLabel = "project_name" - hostnameLabel = "hostname" + namespace = "yorkie" + sdkTypeLabel = "sdk_type" + sdkVersionLabel = "sdk_version" + methodLabel = "grpc_method" + projectIDLabel = "project_id" + projectNameLabel = "project_name" + hostnameLabel = "hostname" + taskTypeLabel = "task_type" + docEventTypeLabel = "doc_event_type" ) var ( @@ -54,12 +56,18 @@ type Metrics struct { serverHandledCounter *prometheus.CounterVec pushPullResponseSeconds prometheus.Histogram - pushPullReceivedChangesTotal prometheus.Counter - pushPullSentChangesTotal prometheus.Counter - pushPullReceivedOperationsTotal prometheus.Counter - pushPullSentOperationsTotal prometheus.Counter + pushPullReceivedChangesTotal *prometheus.CounterVec + pushPullSentChangesTotal *prometheus.CounterVec + pushPullReceivedOperationsTotal *prometheus.CounterVec + pushPullSentOperationsTotal *prometheus.CounterVec pushPullSnapshotDurationSeconds prometheus.Histogram - pushPullSnapshotBytesTotal prometheus.Counter + pushPullSnapshotBytesTotal *prometheus.CounterVec + + backgroundGoroutinesTotal *prometheus.GaugeVec + + watchDocumentConnectionsTotal *prometheus.GaugeVec + watchDocumentEventsTotal *prometheus.CounterVec + watchDocumentEventPayloadBytesTotal *prometheus.CounterVec userAgentTotal *prometheus.CounterVec } @@ -95,32 +103,45 @@ func NewMetrics() (*Metrics, error) { Name: "response_seconds", Help: "The response time of PushPull.", }), - pushPullReceivedChangesTotal: promauto.With(reg).NewCounter(prometheus.CounterOpts{ + pushPullReceivedChangesTotal: promauto.With(reg).NewCounterVec(prometheus.CounterOpts{ Namespace: namespace, Subsystem: "pushpull", Name: "received_changes_total", Help: "The total count of changes included in request packs in PushPull.", + }, []string{ + projectIDLabel, + projectNameLabel, + hostnameLabel, }), - pushPullSentChangesTotal: promauto.With(reg).NewCounter(prometheus.CounterOpts{ + pushPullSentChangesTotal: promauto.With(reg).NewCounterVec(prometheus.CounterOpts{ Namespace: namespace, Subsystem: "pushpull", Name: "sent_changes_total", Help: "The total count of changes included in response packs in PushPull.", + }, []string{ + projectIDLabel, + projectNameLabel, + hostnameLabel, }), - pushPullReceivedOperationsTotal: promauto.With(reg).NewCounter( - prometheus.CounterOpts{ - Namespace: namespace, - Subsystem: "pushpull", - Name: "received_operations_total", - Help: "The total count of operations included in request" + - " packs in PushPull.", - }), - pushPullSentOperationsTotal: promauto.With(reg).NewCounter(prometheus.CounterOpts{ + pushPullReceivedOperationsTotal: promauto.With(reg).NewCounterVec(prometheus.CounterOpts{ + Namespace: namespace, + Subsystem: "pushpull", + Name: "received_operations_total", + Help: "The total count of operations included in request packs in PushPull.", + }, []string{ + projectIDLabel, + projectNameLabel, + hostnameLabel, + }), + pushPullSentOperationsTotal: promauto.With(reg).NewCounterVec(prometheus.CounterOpts{ Namespace: namespace, Subsystem: "pushpull", Name: "sent_operations_total", - Help: "The total count of operations included in response" + - " packs in PushPull.", + Help: "The total count of operations included in response packs in PushPull.", + }, []string{ + projectIDLabel, + projectNameLabel, + hostnameLabel, }), pushPullSnapshotDurationSeconds: promauto.With(reg).NewHistogram(prometheus.HistogramOpts{ Namespace: namespace, @@ -128,11 +149,31 @@ func NewMetrics() (*Metrics, error) { Name: "snapshot_duration_seconds", Help: "The creation time of snapshot for response packs in PushPull.", }), - pushPullSnapshotBytesTotal: promauto.With(reg).NewCounter(prometheus.CounterOpts{ + pushPullSnapshotBytesTotal: promauto.With(reg).NewCounterVec(prometheus.CounterOpts{ Namespace: namespace, Subsystem: "pushpull", Name: "snapshot_bytes_total", Help: "The total bytes of snapshots for response packs in PushPull.", + }, []string{ + projectIDLabel, + projectNameLabel, + hostnameLabel, + }), + backgroundGoroutinesTotal: promauto.With(reg).NewGaugeVec(prometheus.GaugeOpts{ + Namespace: namespace, + Subsystem: "background", + Name: "goroutines_total", + Help: "The total number of goroutines attached by a particular background task.", + }, []string{taskTypeLabel}), + watchDocumentConnectionsTotal: promauto.With(reg).NewGaugeVec(prometheus.GaugeOpts{ + Namespace: namespace, + Subsystem: "stream", + Name: "watch_document_stream_connections_total", + Help: "The total number of document watch stream connections.", + }, []string{ + projectIDLabel, + projectNameLabel, + hostnameLabel, }), userAgentTotal: promauto.With(reg).NewCounterVec(prometheus.CounterOpts{ Namespace: namespace, @@ -147,6 +188,28 @@ func NewMetrics() (*Metrics, error) { projectNameLabel, hostnameLabel, }), + watchDocumentEventsTotal: promauto.With(reg).NewCounterVec(prometheus.CounterOpts{ + Namespace: namespace, + Subsystem: "stream", + Name: "watch_document_events_total", + Help: "The total number of events in document watch stream connections.", + }, []string{ + projectIDLabel, + projectNameLabel, + hostnameLabel, + docEventTypeLabel, + }), + watchDocumentEventPayloadBytesTotal: promauto.With(reg).NewCounterVec(prometheus.CounterOpts{ + Namespace: namespace, + Subsystem: "stream", + Name: "watch_document_event_payload_bytes_total", + Help: "The total bytes of event payloads in document watch stream connections.", + }, []string{ + projectIDLabel, + projectNameLabel, + hostnameLabel, + docEventTypeLabel, + }), } metrics.serverVersion.With(prometheus.Labels{ @@ -164,26 +227,42 @@ func (m *Metrics) ObservePushPullResponseSeconds(seconds float64) { // AddPushPullReceivedChanges sets the number of changes // included in the request pack of PushPull. -func (m *Metrics) AddPushPullReceivedChanges(count int) { - m.pushPullReceivedChangesTotal.Add(float64(count)) +func (m *Metrics) AddPushPullReceivedChanges(hostname string, project *types.Project, count int) { + m.pushPullReceivedChangesTotal.With(prometheus.Labels{ + projectIDLabel: project.ID.String(), + projectNameLabel: project.Name, + hostnameLabel: hostname, + }).Add(float64(count)) } // AddPushPullSentChanges adds the number of changes // included in the response pack of PushPull. -func (m *Metrics) AddPushPullSentChanges(count int) { - m.pushPullSentChangesTotal.Add(float64(count)) +func (m *Metrics) AddPushPullSentChanges(hostname string, project *types.Project, count int) { + m.pushPullSentChangesTotal.With(prometheus.Labels{ + projectIDLabel: project.ID.String(), + projectNameLabel: project.Name, + hostnameLabel: hostname, + }).Add(float64(count)) } // AddPushPullReceivedOperations sets the number of operations // included in the request pack of PushPull. -func (m *Metrics) AddPushPullReceivedOperations(count int) { - m.pushPullReceivedOperationsTotal.Add(float64(count)) +func (m *Metrics) AddPushPullReceivedOperations(hostname string, project *types.Project, count int) { + m.pushPullReceivedOperationsTotal.With(prometheus.Labels{ + projectIDLabel: project.ID.String(), + projectNameLabel: project.Name, + hostnameLabel: hostname, + }).Add(float64(count)) } // AddPushPullSentOperations adds the number of operations // included in the response pack of PushPull. -func (m *Metrics) AddPushPullSentOperations(count int) { - m.pushPullSentOperationsTotal.Add(float64(count)) +func (m *Metrics) AddPushPullSentOperations(hostname string, project *types.Project, count int) { + m.pushPullSentOperationsTotal.With(prometheus.Labels{ + projectIDLabel: project.ID.String(), + projectNameLabel: project.Name, + hostnameLabel: hostname, + }).Add(float64(count)) } // ObservePushPullSnapshotDurationSeconds adds an observation @@ -193,8 +272,12 @@ func (m *Metrics) ObservePushPullSnapshotDurationSeconds(seconds float64) { } // AddPushPullSnapshotBytes adds the snapshot byte size of response pack. -func (m *Metrics) AddPushPullSnapshotBytes(bytes int) { - m.pushPullSnapshotBytesTotal.Add(float64(bytes)) +func (m *Metrics) AddPushPullSnapshotBytes(hostname string, project *types.Project, bytes int) { + m.pushPullSnapshotBytesTotal.With(prometheus.Labels{ + projectIDLabel: project.ID.String(), + projectNameLabel: project.Name, + hostnameLabel: hostname, + }).Add(float64(bytes)) } // AddUserAgent adds the number of user agent. @@ -234,6 +317,66 @@ func (m *Metrics) AddServerHandledCounter( }).Inc() } +// AddBackgroundGoroutines adds the number of goroutines attached by a particular background task. +func (m *Metrics) AddBackgroundGoroutines(taskType string) { + m.backgroundGoroutinesTotal.With(prometheus.Labels{ + taskTypeLabel: taskType, + }).Inc() +} + +// RemoveBackgroundGoroutines removes the number of goroutines attached by a particular background task. +func (m *Metrics) RemoveBackgroundGoroutines(taskType string) { + m.backgroundGoroutinesTotal.With(prometheus.Labels{ + taskTypeLabel: taskType, + }).Dec() +} + +// AddWatchDocumentConnections adds the number of document watch stream connection. +func (m *Metrics) AddWatchDocumentConnections(hostname string, project *types.Project) { + m.watchDocumentConnectionsTotal.With(prometheus.Labels{ + projectIDLabel: project.ID.String(), + projectNameLabel: project.Name, + hostnameLabel: hostname, + }).Inc() +} + +// RemoveWatchDocumentConnections removes the number of document watch stream connection. +func (m *Metrics) RemoveWatchDocumentConnections(hostname string, project *types.Project) { + m.watchDocumentConnectionsTotal.With(prometheus.Labels{ + projectIDLabel: project.ID.String(), + projectNameLabel: project.Name, + hostnameLabel: hostname, + }).Dec() +} + +// AddWatchDocumentEvents adds the number of events in document watch stream connections. +func (m *Metrics) AddWatchDocumentEvents(hostname string, project *types.Project, docEventType types.DocEventType) { + m.watchDocumentEventsTotal.With(prometheus.Labels{ + projectIDLabel: project.ID.String(), + projectNameLabel: project.Name, + hostnameLabel: hostname, + docEventTypeLabel: string(docEventType), + }).Inc() +} + +// AddWatchDocumentEventPayloadBytes adds the bytes of event payload in document watch stream connections. +func (m *Metrics) AddWatchDocumentEventPayloadBytes(hostname string, project *types.Project, + docEventType types.DocEventType, bytes int) { + m.watchDocumentEventsTotal.With(prometheus.Labels{ + projectIDLabel: project.ID.String(), + projectNameLabel: project.Name, + hostnameLabel: hostname, + docEventTypeLabel: string(docEventType), + }).Inc() + + m.watchDocumentEventPayloadBytesTotal.With(prometheus.Labels{ + projectIDLabel: project.ID.String(), + projectNameLabel: project.Name, + hostnameLabel: hostname, + docEventTypeLabel: string(docEventType), + }).Add(float64(bytes)) +} + // Registry returns the registry of this metrics. func (m *Metrics) Registry() *prometheus.Registry { return m.registry diff --git a/server/rpc/admin_server.go b/server/rpc/admin_server.go index 3f3c200fd..6add24e2d 100644 --- a/server/rpc/admin_server.go +++ b/server/rpc/admin_server.go @@ -19,12 +19,14 @@ package rpc import ( "context" "fmt" + "runtime" "connectrpc.com/connect" "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/internal/version" "github.com/yorkie-team/yorkie/pkg/document/key" "github.com/yorkie-team/yorkie/pkg/document/time" "github.com/yorkie-team/yorkie/server/backend" @@ -55,7 +57,7 @@ func (s *adminServer) SignUp( ctx context.Context, req *connect.Request[api.SignUpRequest], ) (*connect.Response[api.SignUpResponse], error) { - fields := &types.SignupFields{Username: &req.Msg.Username, Password: &req.Msg.Password} + fields := &types.UserFields{Username: &req.Msg.Username, Password: &req.Msg.Password} if err := fields.Validate(); err != nil { return nil, err } @@ -95,6 +97,57 @@ func (s *adminServer) LogIn( }), nil } +// DeleteAccount deletes a user. +func (s *adminServer) DeleteAccount( + ctx context.Context, + req *connect.Request[api.DeleteAccountRequest], +) (*connect.Response[api.DeleteAccountResponse], error) { + user, err := users.IsCorrectPassword( + ctx, + s.backend, + req.Msg.Username, + req.Msg.Password, + ) + if err != nil { + return nil, err + } + + err = users.DeleteAccountByName(ctx, s.backend, user.Username) + if err != nil { + return nil, err + } + + return connect.NewResponse(&api.DeleteAccountResponse{}), nil +} + +// ChangePassword changes to new password. +func (s *adminServer) ChangePassword( + ctx context.Context, + req *connect.Request[api.ChangePasswordRequest], +) (*connect.Response[api.ChangePasswordResponse], error) { + fields := &types.UserFields{Username: &req.Msg.Username, Password: &req.Msg.NewPassword} + if err := fields.Validate(); err != nil { + return nil, err + } + + user, err := users.IsCorrectPassword( + ctx, + s.backend, + req.Msg.Username, + req.Msg.CurrentPassword, + ) + if err != nil { + return nil, err + } + + err = users.ChangePassword(ctx, s.backend, user.Username, req.Msg.NewPassword) + if err != nil { + return nil, err + } + + return connect.NewResponse(&api.ChangePasswordResponse{}), nil +} + // CreateProject creates a new project. func (s *adminServer) CreateProject( ctx context.Context, @@ -225,6 +278,7 @@ func (s *adminServer) GetDocuments( s.backend, project, keys, + req.Msg.IncludeSnapshot, ) if err != nil { return nil, err @@ -439,3 +493,15 @@ func (s *adminServer) ListChanges( Changes: pbChanges, }), nil } + +// GetServerVersion get the version of yorkie server. +func (s *adminServer) GetServerVersion( + _ context.Context, + _ *connect.Request[api.GetServerVersionRequest], +) (*connect.Response[api.GetServerVersionResponse], error) { + return connect.NewResponse(&api.GetServerVersionResponse{ + YorkieVersion: version.Version, + GoVersion: runtime.Version(), + BuildDate: version.BuildDate, + }), nil +} diff --git a/server/rpc/connecthelper/status.go b/server/rpc/connecthelper/status.go index 2b330c70d..8708b401b 100644 --- a/server/rpc/connecthelper/status.go +++ b/server/rpc/connecthelper/status.go @@ -151,7 +151,17 @@ func errorToConnectError(err error) (*connect.Error, bool) { cause = errors.Unwrap(cause) } - connectCode, ok := errorToConnectCode[cause] + // NOTE(hackerwins): This prevents panic when the cause is an unhashable + // error. + var connectCode connect.Code + var ok bool + defer func() { + if r := recover(); r != nil { + ok = false + } + }() + + connectCode, ok = errorToConnectCode[cause] if !ok { return nil, false } diff --git a/server/rpc/connecthelper/status_test.go b/server/rpc/connecthelper/status_test.go new file mode 100644 index 000000000..aca1f4d57 --- /dev/null +++ b/server/rpc/connecthelper/status_test.go @@ -0,0 +1,39 @@ +/* + * Copyright 2024 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 connecthelper + +import ( + "testing" + + "connectrpc.com/connect" + "github.com/stretchr/testify/assert" + "go.mongodb.org/mongo-driver/mongo" + + "github.com/yorkie-team/yorkie/api/converter" +) + +func TestStatus(t *testing.T) { + t.Run("errorToConnectCode test", func(t *testing.T) { + status, ok := errorToConnectError(converter.ErrPackRequired) + assert.True(t, ok) + assert.Equal(t, status.Code(), connect.CodeInvalidArgument) + + status, ok = errorToConnectError(mongo.CommandError{}) + assert.False(t, ok) + assert.Nil(t, status) + }) +} diff --git a/server/rpc/httphealth/httphealth.go b/server/rpc/httphealth/httphealth.go new file mode 100644 index 000000000..ab3a5a0d6 --- /dev/null +++ b/server/rpc/httphealth/httphealth.go @@ -0,0 +1,66 @@ +/* + * Copyright 2024 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 httphealth uses http GET to provide a health check for the server. +package httphealth + +import ( + "encoding/json" + "net/http" + + "connectrpc.com/grpchealth" +) + +// HealthV1ServiceName is the fully-qualified name of the v1 version of the health service. +const HealthV1ServiceName = "/yorkie.v1.YorkieService/health" + +// CheckResponse represents the response structure for health checks. +type CheckResponse struct { + Status string `json:"status"` +} + +// NewHandler creates a new HTTP handler for health checks. +func NewHandler(checker grpchealth.Checker) (string, http.Handler) { + check := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet && r.Method != http.MethodHead { + http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) + return + } + var checkRequest grpchealth.CheckRequest + service := r.URL.Query().Get("service") + if service != "" { + checkRequest.Service = service + } + checkResponse, err := checker.Check(r.Context(), &checkRequest) + if err != nil { + http.Error(w, err.Error(), http.StatusNotFound) + return + } + resp, err := json.Marshal(CheckResponse{checkResponse.Status.String()}) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + if r.Method == http.MethodGet { + if _, err := w.Write(resp); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + } + }) + return HealthV1ServiceName, check +} diff --git a/server/rpc/interceptors/admin.go b/server/rpc/interceptors/admin.go index 1f6ab5373..ee59f4734 100644 --- a/server/rpc/interceptors/admin.go +++ b/server/rpc/interceptors/admin.go @@ -42,7 +42,9 @@ func isAdminService(method string) bool { func isRequiredAuth(method string) bool { return method != "/yorkie.v1.AdminService/LogIn" && - method != "/yorkie.v1.AdminService/SignUp" + method != "/yorkie.v1.AdminService/SignUp" && + method != "/yorkie.v1.AdminService/ChangePassword" && + method != "/yorkie.v1.AdminService/DeleteAccount" } // AdminServiceInterceptor is an interceptor for building additional context diff --git a/server/rpc/server.go b/server/rpc/server.go index 85f57b521..cfd06ad88 100644 --- a/server/rpc/server.go +++ b/server/rpc/server.go @@ -36,6 +36,7 @@ import ( "github.com/yorkie-team/yorkie/server/backend" "github.com/yorkie-team/yorkie/server/logging" "github.com/yorkie-team/yorkie/server/rpc/auth" + "github.com/yorkie-team/yorkie/server/rpc/httphealth" "github.com/yorkie-team/yorkie/server/rpc/interceptors" ) @@ -62,16 +63,18 @@ func NewServer(conf *Config, be *backend.Backend) (*Server, error) { ), } - yorkieServiceCtx, yorkieServiceCancel := context.WithCancel(context.Background()) - mux := http.NewServeMux() - mux.Handle(v1connect.NewYorkieServiceHandler(newYorkieServer(yorkieServiceCtx, be), opts...)) - mux.Handle(v1connect.NewAdminServiceHandler(newAdminServer(be, tokenManager), opts...)) - mux.Handle(grpchealth.NewHandler(grpchealth.NewStaticChecker( + healthChecker := grpchealth.NewStaticChecker( grpchealth.HealthV1ServiceName, v1connect.YorkieServiceName, v1connect.AdminServiceName, - ))) + ) + yorkieServiceCtx, yorkieServiceCancel := context.WithCancel(context.Background()) + mux := http.NewServeMux() + mux.Handle(v1connect.NewYorkieServiceHandler(newYorkieServer(yorkieServiceCtx, be), opts...)) + mux.Handle(v1connect.NewAdminServiceHandler(newAdminServer(be, tokenManager), opts...)) + mux.Handle(grpchealth.NewHandler(healthChecker)) + mux.Handle(httphealth.NewHandler(healthChecker)) // TODO(hackerwins): We need to provide proper http server configuration. return &Server{ conf: conf, diff --git a/server/rpc/server_test.go b/server/rpc/server_test.go index 8c3d3ff3a..159c686ed 100644 --- a/server/rpc/server_test.go +++ b/server/rpc/server_test.go @@ -70,6 +70,7 @@ func TestMain(m *testing.M) { be, err := backend.New(&backend.Config{ AdminUser: helper.AdminUser, AdminPassword: helper.AdminPassword, + UseDefaultProject: helper.UseDefaultProject, ClientDeactivateThreshold: helper.ClientDeactivateThreshold, SnapshotThreshold: helper.SnapshotThreshold, AuthWebhookCacheSize: helper.AuthWebhookSize, @@ -182,6 +183,14 @@ func TestAdminRPCServerBackend(t *testing.T) { testcases.RunAdminLoginTest(t, testAdminClient) }) + t.Run("admin delete account test", func(t *testing.T) { + testcases.RunAdminDeleteAccountTest(t, testAdminClient) + }) + + t.Run("admin change password test", func(t *testing.T) { + testcases.RunAdminChangePasswordTest(t, testAdminClient) + }) + t.Run("admin create project test", func(t *testing.T) { testcases.RunAdminCreateProjectTest(t, testAdminClient, testAdminAuthInterceptor) }) @@ -209,6 +218,10 @@ func TestAdminRPCServerBackend(t *testing.T) { t.Run("admin list changes test", func(t *testing.T) { testcases.RunAdminListChangesTest(t, testClient, testAdminClient, testAdminAuthInterceptor) }) + + t.Run("admin get server version test", func(t *testing.T) { + testcases.RunAdminGetServerVersionTest(t, testAdminClient) + }) } func TestConfig_Validate(t *testing.T) { diff --git a/server/rpc/testcases/testcases.go b/server/rpc/testcases/testcases.go index 7f79c894c..aad0e63e8 100644 --- a/server/rpc/testcases/testcases.go +++ b/server/rpc/testcases/testcases.go @@ -648,7 +648,7 @@ func RunAdminSignUpTest( testAdminClient v1connect.AdminServiceClient, ) { adminUser := helper.TestSlugName(t) - adminPassword := helper.AdminPassword + "123!" + adminPassword := helper.AdminPasswordForSignUp _, err := testAdminClient.SignUp( context.Background(), @@ -697,6 +697,113 @@ func RunAdminLoginTest( assert.Equal(t, connecthelper.CodeOf(database.ErrMismatchedPassword), converter.ErrorCodeOf(err)) } +// RunAdminDeleteAccountTest runs the admin delete user test. +func RunAdminDeleteAccountTest( + t *testing.T, + testAdminClient v1connect.AdminServiceClient, +) { + adminUser := helper.TestSlugName(t) + adminPassword := helper.AdminPasswordForSignUp + + _, err := testAdminClient.SignUp( + context.Background(), + connect.NewRequest(&api.SignUpRequest{ + Username: adminUser, + Password: adminPassword, + }, + )) + assert.NoError(t, err) + + _, err = testAdminClient.DeleteAccount( + context.Background(), + connect.NewRequest(&api.DeleteAccountRequest{ + Username: adminUser, + Password: adminPassword, + }, + )) + assert.NoError(t, err) + + // try to delete user with not existing username + _, err = testAdminClient.DeleteAccount( + context.Background(), + connect.NewRequest(&api.DeleteAccountRequest{ + Username: adminUser, + Password: adminPassword, + }, + )) + assert.Equal(t, connect.CodeNotFound, connect.CodeOf(err)) + assert.Equal(t, connecthelper.CodeOf(database.ErrUserNotFound), converter.ErrorCodeOf(err)) +} + +// RunAdminChangePasswordTest runs the admin change password user test. +func RunAdminChangePasswordTest( + t *testing.T, + testAdminClient v1connect.AdminServiceClient, +) { + adminUser := helper.TestSlugName(t) + adminPassword := helper.AdminPasswordForSignUp + + _, err := testAdminClient.SignUp( + context.Background(), + connect.NewRequest(&api.SignUpRequest{ + Username: adminUser, + Password: adminPassword, + }, + )) + assert.NoError(t, err) + + _, err = testAdminClient.LogIn( + context.Background(), + connect.NewRequest(&api.LogInRequest{ + Username: adminUser, + Password: adminPassword, + }, + )) + assert.NoError(t, err) + + newAdminPassword := helper.AdminPassword + "12345!" + _, err = testAdminClient.ChangePassword( + context.Background(), + connect.NewRequest(&api.ChangePasswordRequest{ + Username: adminUser, + CurrentPassword: adminPassword, + NewPassword: newAdminPassword, + }, + )) + assert.NoError(t, err) + + // log in fail when try to log in with old password + _, err = testAdminClient.LogIn( + context.Background(), + connect.NewRequest(&api.LogInRequest{ + Username: adminUser, + Password: adminPassword, + }, + )) + assert.Equal(t, connect.CodeUnauthenticated, connect.CodeOf(err)) + assert.Equal(t, connecthelper.CodeOf(database.ErrMismatchedPassword), converter.ErrorCodeOf(err)) + + _, err = testAdminClient.LogIn( + context.Background(), + connect.NewRequest(&api.LogInRequest{ + Username: adminUser, + Password: newAdminPassword, + }, + )) + assert.NoError(t, err) + + // try to change password with invalid password + _, err = testAdminClient.ChangePassword( + context.Background(), + connect.NewRequest(&api.ChangePasswordRequest{ + Username: adminUser, + CurrentPassword: adminPassword, + NewPassword: invalidSlugName, + }, + )) + assert.Equal(t, connect.CodeInvalidArgument, connect.CodeOf(err)) +} + // RunAdminCreateProjectTest runs the CreateProject test in admin. func RunAdminCreateProjectTest( t *testing.T, @@ -1018,3 +1125,24 @@ func RunAdminListChangesTest( assert.Equal(t, connect.CodeNotFound, connect.CodeOf(err)) assert.Equal(t, connecthelper.CodeOf(database.ErrDocumentNotFound), converter.ErrorCodeOf(err)) } + +// RunAdminGetServerVersionTest runs the GetServerVersion test in admin. +func RunAdminGetServerVersionTest( + t *testing.T, + testAdminClient v1connect.AdminServiceClient, +) { + versionResponse, err := testAdminClient.GetServerVersion( + context.Background(), + connect.NewRequest(&api.GetServerVersionRequest{}), + ) + + assert.NoError(t, err) + assert.NotNil(t, versionResponse) + + responseMsg := versionResponse.Msg + + assert.NotEmpty(t, responseMsg.YorkieVersion) + assert.NotEmpty(t, responseMsg.GoVersion) + assert.Regexp(t, `^\d+\.\d+\.\d+$`, responseMsg.YorkieVersion) + assert.Regexp(t, `^go\d+\.\d+(\.\d+)?$`, responseMsg.GoVersion) +} diff --git a/server/rpc/yorkie_server.go b/server/rpc/yorkie_server.go index 22f5ee995..6303e58ea 100644 --- a/server/rpc/yorkie_server.go +++ b/server/rpc/yorkie_server.go @@ -430,8 +430,13 @@ func (s *yorkieServer) WatchDocument( logging.From(ctx).Error(err) return err } + s.backend.Metrics.AddWatchDocumentConnections(s.backend.Config.Hostname, project) defer func() { - s.unwatchDoc(subscription, docRefKey) + if err := s.unwatchDoc(ctx, subscription, docRefKey); err != nil { + logging.From(ctx).Error(err) + } else { + s.backend.Metrics.RemoveWatchDocumentConnections(s.backend.Config.Hostname, project) + } }() var pbClientIDs []string @@ -460,7 +465,7 @@ func (s *yorkieServer) WatchDocument( return err } - if err := stream.Send(&api.WatchDocumentResponse{ + response := &api.WatchDocumentResponse{ Body: &api.WatchDocumentResponse_Event{ Event: &api.DocEvent{ Type: eventType, @@ -471,9 +476,16 @@ func (s *yorkieServer) WatchDocument( }, }, }, - }); err != nil { + } + if err := stream.Send(response); err != nil { return err } + s.backend.Metrics.AddWatchDocumentEventPayloadBytes( + s.backend.Config.Hostname, + project, + event.Type, + event.Body.PayloadLen(), + ) } } } @@ -576,16 +588,27 @@ func (s *yorkieServer) watchDoc( DocumentRefKey: documentRefKey, }, ) + s.backend.Metrics.AddWatchDocumentEventPayloadBytes( + s.backend.Config.Hostname, + projects.From(ctx), + types.DocumentWatchedEvent, + 0, + ) return subscription, clientIDs, nil } func (s *yorkieServer) unwatchDoc( + ctx context.Context, subscription *sync.Subscription, documentRefKey types.DocRefKey, -) { - ctx := context.Background() - _ = s.backend.Coordinator.Unsubscribe(ctx, documentRefKey, subscription) +) error { + err := s.backend.Coordinator.Unsubscribe(ctx, documentRefKey, subscription) + if err != nil { + logging.From(ctx).Error(err) + return err + } + s.backend.Coordinator.Publish( ctx, subscription.Subscriber(), @@ -595,6 +618,14 @@ func (s *yorkieServer) unwatchDoc( DocumentRefKey: documentRefKey, }, ) + s.backend.Metrics.AddWatchDocumentEventPayloadBytes( + s.backend.Config.Hostname, + projects.From(ctx), + types.DocumentUnwatchedEvent, + 0, + ) + + return nil } func (s *yorkieServer) Broadcast( @@ -640,11 +671,12 @@ func (s *yorkieServer) Broadcast( return nil, err } + docEventType := types.DocumentBroadcastEvent s.backend.Coordinator.Publish( ctx, clientID, sync.DocEvent{ - Type: types.DocumentBroadcastEvent, + Type: docEventType, Publisher: clientID, DocumentRefKey: docRefKey, Body: types.DocEventBody{ @@ -653,6 +685,8 @@ func (s *yorkieServer) Broadcast( }, }, ) + s.backend.Metrics.AddWatchDocumentEventPayloadBytes(s.backend.Config.Hostname, project, docEventType, + len(req.Msg.Payload)) return connect.NewResponse(&api.BroadcastResponse{}), nil } diff --git a/server/server.go b/server/server.go index 08df35526..6a777f5d5 100644 --- a/server/server.go +++ b/server/server.go @@ -26,6 +26,7 @@ import ( "github.com/yorkie-team/yorkie/api/types" "github.com/yorkie-team/yorkie/client" "github.com/yorkie-team/yorkie/server/backend" + "github.com/yorkie-team/yorkie/server/backend/database" "github.com/yorkie-team/yorkie/server/clients" "github.com/yorkie-team/yorkie/server/profiling" "github.com/yorkie-team/yorkie/server/profiling/prometheus" @@ -93,6 +94,14 @@ func (r *Yorkie) Start() error { r.lock.Lock() defer r.lock.Unlock() + if err := r.RegisterHousekeepingTasks(r.backend); err != nil { + return err + } + + if err := r.backend.Start(); err != nil { + return err + } + if r.profilingServer != nil { err := r.profilingServer.Start() if err != nil { @@ -148,6 +157,31 @@ func (r *Yorkie) DeactivateClient(ctx context.Context, c1 *client.Client) error return err } +// RegisterHousekeepingTasks registers housekeeping tasks. +func (r *Yorkie) RegisterHousekeepingTasks(be *backend.Backend) error { + interval, err := be.Housekeeping.Config.ParseInterval() + if err != nil { + return err + } + + housekeepingLastProjectID := database.DefaultProjectID + return be.Housekeeping.RegisterTask(interval, func(ctx context.Context) error { + lastProjectID, err := clients.DeactivateInactives( + ctx, + be, + be.Housekeeping.Config.CandidatesLimitPerProject, + be.Housekeeping.Config.ProjectFetchSize, + housekeepingLastProjectID, + ) + if err != nil { + return err + } + + housekeepingLastProjectID = lastProjectID + return nil + }) +} + // DefaultProject returns the default project. func (r *Yorkie) DefaultProject(ctx context.Context) (*types.Project, error) { return projects.GetProjectFromAPIKey(ctx, r.backend, "") diff --git a/server/users/users.go b/server/users/users.go index e4adc6a66..66831fd8d 100644 --- a/server/users/users.go +++ b/server/users/users.go @@ -94,3 +94,35 @@ func GetUserByID( } return info.ToUser(), nil } + +// DeleteAccountByName deletes a user by name. +func DeleteAccountByName( + ctx context.Context, + be *backend.Backend, + username string, +) error { + if err := be.DB.DeleteUserInfoByName(ctx, username); err != nil { + return err + } + + return nil +} + +// ChangePassword changes the password for a user. +func ChangePassword( + ctx context.Context, + be *backend.Backend, + username, + newPassword string, +) error { + hashedNewPassword, err := database.HashedPassword(newPassword) + if err != nil { + return fmt.Errorf("cannot hash newPassword: %w", err) + } + + if err := be.DB.ChangeUserPassword(ctx, username, hashedNewPassword); err != nil { + return err + } + + return nil +} diff --git a/test/bench/tree_editing_bench_test.go b/test/bench/tree_editing_bench_test.go new file mode 100644 index 000000000..a05215dbc --- /dev/null +++ b/test/bench/tree_editing_bench_test.go @@ -0,0 +1,69 @@ +//go:build bench + +/* + * Copyright 2024 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 bench + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/yorkie-team/yorkie/api/converter" + "github.com/yorkie-team/yorkie/pkg/document/crdt" + "github.com/yorkie-team/yorkie/pkg/document/json" + "github.com/yorkie-team/yorkie/test/helper" +) + +func BenchmarkTree(b *testing.B) { + verticesCounts := []int{10000, 20000, 30000} + + for _, cnt := range verticesCounts { + root := buildTree(cnt) + b.ResetTimer() + + b.Run(fmt.Sprintf("%d vertices to protobuf", cnt), func(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = converter.ToTreeNodes(root) + } + }) + + b.Run(fmt.Sprintf("%d vertices from protobuf", cnt), func(b *testing.B) { + for i := 0; i < b.N; i++ { + pbNodes := converter.ToTreeNodes(root) + _, err := converter.FromTreeNodes(pbNodes) + assert.NoError(b, err) + } + }) + } +} + +// buildTree creates a tree with the given number of vertices. +func buildTree(vertexCnt int) *crdt.TreeNode { + children := make([]json.TreeNode, vertexCnt) + for i := 0; i < vertexCnt; i++ { + children[i] = json.TreeNode{ + Type: "p", Children: []json.TreeNode{{Type: "text", Value: "a"}}, + } + } + + return helper.BuildTreeNode(&json.TreeNode{ + Type: "r", + Children: children, + }) +} diff --git a/test/sharding/server_test.go b/test/complex/main_test.go similarity index 60% rename from test/sharding/server_test.go rename to test/complex/main_test.go index 6e906fb4a..9ce84b62d 100644 --- a/test/sharding/server_test.go +++ b/test/complex/main_test.go @@ -1,4 +1,4 @@ -//go:build sharding +//go:build complex /* * Copyright 2023 The Yorkie Authors. All rights reserved. @@ -16,7 +16,7 @@ * limitations under the License. */ -package sharding +package complex import ( "context" @@ -27,20 +27,30 @@ import ( "testing" "connectrpc.com/connect" - + "github.com/stretchr/testify/assert" "github.com/yorkie-team/yorkie/admin" "github.com/yorkie-team/yorkie/api/yorkie/v1/v1connect" "github.com/yorkie-team/yorkie/client" + "github.com/yorkie-team/yorkie/pkg/document" "github.com/yorkie-team/yorkie/server/backend" "github.com/yorkie-team/yorkie/server/backend/database" "github.com/yorkie-team/yorkie/server/backend/database/mongo" "github.com/yorkie-team/yorkie/server/backend/housekeeping" "github.com/yorkie-team/yorkie/server/profiling/prometheus" "github.com/yorkie-team/yorkie/server/rpc" - "github.com/yorkie-team/yorkie/server/rpc/testcases" "github.com/yorkie-team/yorkie/test/helper" ) +type testResult struct { + flag bool + resultDesc string +} + +type clientAndDocPair struct { + cli *client.Client + doc *document.Document +} + var ( shardedDBNameForServer = "test-yorkie-meta-server" testRPCServer *rpc.Server @@ -65,6 +75,7 @@ func TestMain(m *testing.M) { be, err := backend.New(&backend.Config{ AdminUser: helper.AdminUser, AdminPassword: helper.AdminPassword, + UseDefaultProject: helper.UseDefaultProject, ClientDeactivateThreshold: helper.ClientDeactivateThreshold, SnapshotThreshold: helper.SnapshotThreshold, AuthWebhookCacheSize: helper.AuthWebhookSize, @@ -131,74 +142,53 @@ func TestMain(m *testing.M) { os.Exit(code) } -func TestSDKRPCServerBackendWithShardedDB(t *testing.T) { - t.Run("activate/deactivate client test", func(t *testing.T) { - testcases.RunActivateAndDeactivateClientTest(t, testClient) - }) - - t.Run("attach/detach document test", func(t *testing.T) { - testcases.RunAttachAndDetachDocumentTest(t, testClient) - }) - - t.Run("attach/detach on removed document test", func(t *testing.T) { - testcases.RunAttachAndDetachRemovedDocumentTest(t, testClient) - }) - - t.Run("push/pull changes test", func(t *testing.T) { - testcases.RunPushPullChangeTest(t, testClient) - }) - - t.Run("push/pull on removed document test", func(t *testing.T) { - testcases.RunPushPullChangeOnRemovedDocumentTest(t, testClient) - }) +func syncClientsThenCheckEqual(t *testing.T, pairs []clientAndDocPair) bool { + assert.True(t, len(pairs) > 1) + ctx := context.Background() + // Save own changes and get previous changes. + for i, pair := range pairs { + fmt.Printf("before d%d: %s\n", i+1, pair.doc.Marshal()) + err := pair.cli.Sync(ctx) + assert.NoError(t, err) + } - t.Run("remove document test", func(t *testing.T) { - testcases.RunRemoveDocumentTest(t, testClient) - }) + // Get last client changes. + // Last client get all precede changes in above loop. + for _, pair := range pairs[:len(pairs)-1] { + err := pair.cli.Sync(ctx) + assert.NoError(t, err) + } - t.Run("remove document with invalid client state test", func(t *testing.T) { - testcases.RunRemoveDocumentWithInvalidClientStateTest(t, testClient) - }) + // Assert start. + expected := pairs[0].doc.Marshal() + fmt.Printf("after d1: %s\n", expected) + for i, pair := range pairs[1:] { + v := pair.doc.Marshal() + fmt.Printf("after d%d: %s\n", i+2, v) + if expected != v { + return false + } + } - t.Run("watch document test", func(t *testing.T) { - testcases.RunWatchDocumentTest(t, testClient) - }) + return true } -func TestAdminRPCServerBackendWithShardedDB(t *testing.T) { - t.Run("admin signup test", func(t *testing.T) { - testcases.RunAdminSignUpTest(t, testAdminClient) - }) - - t.Run("admin login test", func(t *testing.T) { - testcases.RunAdminLoginTest(t, testAdminClient) - }) - - t.Run("admin create project test", func(t *testing.T) { - testcases.RunAdminCreateProjectTest(t, testAdminClient, testAdminAuthInterceptor) - }) - - t.Run("admin list projects test", func(t *testing.T) { - testcases.RunAdminListProjectsTest(t, testAdminClient, testAdminAuthInterceptor) - }) - - t.Run("admin get project test", func(t *testing.T) { - testcases.RunAdminGetProjectTest(t, testAdminClient, testAdminAuthInterceptor) - }) +// 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(testRPCAddr) + assert.NoError(t, err) + assert.NoError(t, c.Activate(context.Background())) - t.Run("admin update project test", func(t *testing.T) { - testcases.RunAdminUpdateProjectTest(t, testAdminClient, testAdminAuthInterceptor) - }) - - t.Run("admin list documents test", func(t *testing.T) { - testcases.RunAdminListDocumentsTest(t, testAdminClient, testAdminAuthInterceptor) - }) - - t.Run("admin get document test", func(t *testing.T) { - testcases.RunAdminGetDocumentTest(t, testClient, testAdminClient, testAdminAuthInterceptor) - }) + clients = append(clients, c) + } + return +} - t.Run("admin list changes test", func(t *testing.T) { - testcases.RunAdminListChangesTest(t, testClient, testAdminClient, testAdminAuthInterceptor) - }) +// deactivateAndCloseClients deactivates and closes the given clients. +func deactivateAndCloseClients(t *testing.T, clients []*client.Client) { + for _, c := range clients { + assert.NoError(t, c.Deactivate(context.Background())) + assert.NoError(t, c.Close()) + } } diff --git a/test/sharding/mongo_client_test.go b/test/complex/mongo_client_test.go similarity index 93% rename from test/sharding/mongo_client_test.go rename to test/complex/mongo_client_test.go index c041ec977..2fd6691fb 100644 --- a/test/sharding/mongo_client_test.go +++ b/test/complex/mongo_client_test.go @@ -1,4 +1,4 @@ -//go:build sharding +//go:build complex /* * Copyright 2023 The Yorkie Authors. All rights reserved. @@ -16,7 +16,7 @@ * limitations under the License. */ -package sharding +package complex import ( "context" @@ -72,6 +72,10 @@ func TestClientWithShardedDB(t *testing.T) { testcases.RunFindDocInfoTest(t, cli, dummyProjectID) }) + t.Run("RunFindDocInfosByKeys test", func(t *testing.T) { + testcases.RunFindDocInfosByKeysTest(t, cli, dummyProjectID) + }) + t.Run("RunFindDocInfosByQuery test", func(t *testing.T) { t.Skip("TODO(hackerwins): the order of docInfos is different with memDB") testcases.RunFindDocInfosByQueryTest(t, cli, projectOneID) @@ -81,6 +85,10 @@ func TestClientWithShardedDB(t *testing.T) { testcases.RunFindChangesBetweenServerSeqsTest(t, cli, dummyProjectID) }) + t.Run("RunFindChangeInfosBetweenServerSeqsTest test", func(t *testing.T) { + testcases.RunFindChangeInfosBetweenServerSeqsTest(t, cli, dummyProjectID) + }) + t.Run("RunFindClosestSnapshotInfo test", func(t *testing.T) { testcases.RunFindClosestSnapshotInfoTest(t, cli, dummyProjectID) }) diff --git a/test/complex/server_test.go b/test/complex/server_test.go new file mode 100644 index 000000000..cacc41186 --- /dev/null +++ b/test/complex/server_test.go @@ -0,0 +1,105 @@ +//go:build complex + +/* + * 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 complex + +import ( + "testing" + + "github.com/yorkie-team/yorkie/server/rpc/testcases" +) + +func TestSDKRPCServerBackendWithShardedDB(t *testing.T) { + t.Run("activate/deactivate client test", func(t *testing.T) { + testcases.RunActivateAndDeactivateClientTest(t, testClient) + }) + + t.Run("attach/detach document test", func(t *testing.T) { + testcases.RunAttachAndDetachDocumentTest(t, testClient) + }) + + t.Run("attach/detach on removed document test", func(t *testing.T) { + testcases.RunAttachAndDetachRemovedDocumentTest(t, testClient) + }) + + t.Run("push/pull changes test", func(t *testing.T) { + testcases.RunPushPullChangeTest(t, testClient) + }) + + t.Run("push/pull on removed document test", func(t *testing.T) { + testcases.RunPushPullChangeOnRemovedDocumentTest(t, testClient) + }) + + t.Run("remove document test", func(t *testing.T) { + testcases.RunRemoveDocumentTest(t, testClient) + }) + + t.Run("remove document with invalid client state test", func(t *testing.T) { + testcases.RunRemoveDocumentWithInvalidClientStateTest(t, testClient) + }) + + t.Run("watch document test", func(t *testing.T) { + testcases.RunWatchDocumentTest(t, testClient) + }) +} + +func TestAdminRPCServerBackendWithShardedDB(t *testing.T) { + t.Run("admin signup test", func(t *testing.T) { + testcases.RunAdminSignUpTest(t, testAdminClient) + }) + + t.Run("admin login test", func(t *testing.T) { + testcases.RunAdminLoginTest(t, testAdminClient) + }) + + t.Run("admin delete account test", func(t *testing.T) { + testcases.RunAdminDeleteAccountTest(t, testAdminClient) + }) + + t.Run("admin change password test", func(t *testing.T) { + testcases.RunAdminChangePasswordTest(t, testAdminClient) + }) + + t.Run("admin create project test", func(t *testing.T) { + testcases.RunAdminCreateProjectTest(t, testAdminClient, testAdminAuthInterceptor) + }) + + t.Run("admin list projects test", func(t *testing.T) { + testcases.RunAdminListProjectsTest(t, testAdminClient, testAdminAuthInterceptor) + }) + + t.Run("admin get project test", func(t *testing.T) { + testcases.RunAdminGetProjectTest(t, testAdminClient, testAdminAuthInterceptor) + }) + + t.Run("admin update project test", func(t *testing.T) { + testcases.RunAdminUpdateProjectTest(t, testAdminClient, testAdminAuthInterceptor) + }) + + t.Run("admin list documents test", func(t *testing.T) { + testcases.RunAdminListDocumentsTest(t, testAdminClient, testAdminAuthInterceptor) + }) + + t.Run("admin get document test", func(t *testing.T) { + testcases.RunAdminGetDocumentTest(t, testClient, testAdminClient, testAdminAuthInterceptor) + }) + + t.Run("admin list changes test", func(t *testing.T) { + testcases.RunAdminListChangesTest(t, testClient, testAdminClient, testAdminAuthInterceptor) + }) +} diff --git a/test/integration/tree_concurrency_test.go b/test/complex/tree_concurrency_test.go similarity index 99% rename from test/integration/tree_concurrency_test.go rename to test/complex/tree_concurrency_test.go index b342bebcb..b7e900f5d 100644 --- a/test/integration/tree_concurrency_test.go +++ b/test/complex/tree_concurrency_test.go @@ -1,4 +1,4 @@ -//go:build integration +//go:build complex /* * Copyright 2024 The Yorkie Authors. All rights reserved. @@ -16,7 +16,7 @@ * limitations under the License. */ -package integration +package complex import ( "context" @@ -52,11 +52,6 @@ func parseSimpleXML(s string) []string { return res } -type testResult struct { - flag bool - resultDesc string -} - type rangeSelector int const ( diff --git a/test/helper/helper.go b/test/helper/helper.go index 63d97a358..f007b5b9a 100644 --- a/test/helper/helper.go +++ b/test/helper/helper.go @@ -64,6 +64,8 @@ var ( AdminUser = server.DefaultAdminUser AdminPassword = server.DefaultAdminPassword + AdminPasswordForSignUp = AdminPassword + "123!" + UseDefaultProject = true HousekeepingInterval = 10 * gotime.Second HousekeepingCandidatesLimitPerProject = 10 HousekeepingProjectFetchSize = 10 diff --git a/test/integration/array_test.go b/test/integration/array_test.go index deded6e62..56e68f338 100644 --- a/test/integration/array_test.go +++ b/test/integration/array_test.go @@ -470,3 +470,139 @@ func TestArraySet(t *testing.T) { }) } } + +func TestArrayConcurrencyTable(t *testing.T) { + clients := activeClients(t, 2) + c0, c1 := clients[0], clients[1] + defer deactivateAndCloseClients(t, clients) + + initArr := []int{1, 2, 3, 4} + initMarshal := `[1,2,3,4]` + oneIdx := 1 + otherIdxs := []int{2, 3} + newValues := []int{5, 6} + + type arrayOp struct { + opName string + executor func(*json.Array, int) + } + + // NOTE(junseo): It tests all (op1, op2) pairs in operations. + // `oneIdx` is the index where both op1 and op2 reference. + // `opName` represents the parameter of operation selected as `oneIdx'. + // `otherIdxs` ensures that indexs other than `oneIdx` are not duplicated. + operations := []arrayOp{ + // insert + {"insert.prev", func(a *json.Array, cid int) { + a.InsertIntegerAfter(oneIdx, newValues[cid]) + }}, + {"insert.prev.next", func(a *json.Array, cid int) { + a.InsertIntegerAfter(oneIdx-1, newValues[cid]) + }}, + + // move + {"move.prev", func(a *json.Array, cid int) { + a.MoveAfterByIndex(oneIdx, otherIdxs[cid]) + }}, + {"move.prev.next", func(a *json.Array, cid int) { + a.MoveAfterByIndex(oneIdx-1, otherIdxs[cid]) + }}, + {"move.target", func(a *json.Array, cid int) { + a.MoveAfterByIndex(otherIdxs[cid], oneIdx) + }}, + + // set by index + {"set.target", func(a *json.Array, cid int) { + a.SetInteger(oneIdx, newValues[cid]) + }}, + + // remove + {"remove.target", func(a *json.Array, cid int) { + a.Delete(oneIdx) + }}, + } + + ctx := context.Background() + d0 := document.New(helper.TestDocKey(t)) + assert.NoError(t, c0.Attach(ctx, d0)) + d1 := document.New(helper.TestDocKey(t)) + assert.NoError(t, c1.Attach(ctx, d1)) + + runTest := func(op1, op2 arrayOp) testResult { + assert.NoError(t, d0.Update(func(root *json.Object, p *presence.Presence) error { + root.SetNewArray("a").AddInteger(initArr...) + assert.Equal(t, initMarshal, root.GetArray("a").Marshal()) + return nil + })) + + assert.NoError(t, c0.Sync(ctx)) + assert.NoError(t, c1.Sync(ctx)) + + assert.NoError(t, d0.Update(func(root *json.Object, p *presence.Presence) error { + op1.executor(root.GetArray("a"), 0) + return nil + })) + + assert.NoError(t, d1.Update(func(root *json.Object, p *presence.Presence) error { + op2.executor(root.GetArray("a"), 1) + return nil + })) + + flag := syncClientsThenCheckEqual(t, []clientAndDocPair{{c0, d0}, {c1, d1}}) + if flag { + return testResult{flag, `pass`} + } + return testResult{flag, `different result`} + } + + for _, op1 := range operations { + for _, op2 := range operations { + t.Run(op1.opName+" vs "+op2.opName, func(t *testing.T) { + result := runTest(op1, op2) + if !result.flag { + t.Skip(result.resultDesc) + } + }) + } + } +} + +func TestArraySetByIndex(t *testing.T) { + clients := activeClients(t, 2) + c1, c2 := clients[0], clients[1] + defer deactivateAndCloseClients(t, clients) + + t.Run("array set simple test", func(t *testing.T) { + ctx := context.Background() + d1 := document.New(helper.TestDocKey(t)) + err := c1.Attach(ctx, d1) + assert.NoError(t, err) + + d2 := document.New(helper.TestDocKey(t)) + err = c2.Attach(ctx, d2) + assert.NoError(t, err) + + assert.NoError(t, d1.Update(func(root *json.Object, p *presence.Presence) error { + root.SetNewArray("k1").AddInteger(-1, -2, -3) + assert.Equal(t, `{"k1":[-1,-2,-3]}`, root.Marshal()) + return nil + }, "add -1, -2, -3 by c1")) + + assert.NoError(t, c1.Sync(ctx)) + assert.NoError(t, c2.Sync(ctx)) + + assert.NoError(t, d2.Update(func(root *json.Object, p *presence.Presence) error { + root.GetArray("k1").SetInteger(1, -4) + assert.Equal(t, `{"k1":[-1,-4,-3]}`, root.Marshal()) + return nil + }, "set k1[1] to -4 by c2")) + + assert.NoError(t, d1.Update(func(root *json.Object, p *presence.Presence) error { + root.GetArray("k1").SetInteger(0, -5) + assert.Equal(t, `{"k1":[-5,-2,-3]}`, root.Marshal()) + return nil + }, "set k1[0] to -5 by c1")) + + syncClientsThenAssertEqual(t, []clientAndDocPair{{c1, d1}, {c2, d2}}) + }) +} diff --git a/test/integration/document_test.go b/test/integration/document_test.go index 2451723d7..3b82dfe03 100644 --- a/test/integration/document_test.go +++ b/test/integration/document_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/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" @@ -831,3 +832,299 @@ func TestDocumentWithProjects(t *testing.T) { assert.NotEqual(t, 0, len(docs[0].Snapshot)) }) } + +func TestDocumentWithInitialRoot(t *testing.T) { + clients := activeClients(t, 3) + c1, c2, c3 := clients[0], clients[1], clients[2] + defer deactivateAndCloseClients(t, clients) + + t.Run("attach with InitialRoot test", func(t *testing.T) { + ctx := context.Background() + doc1 := document.New(helper.TestDocKey(t)) + + // 01. attach and initialize document + assert.NoError(t, c1.Attach(ctx, doc1, client.WithInitialRoot(map[string]any{ + "counter": json.NewCounter(0, crdt.LongCnt), + "content": map[string]any{ + "x": 1, + "y": 1, + }, + }))) + assert.True(t, doc1.IsAttached()) + assert.Equal(t, `{"content":{"x":1,"y":1},"counter":0}`, doc1.Marshal()) + assert.NoError(t, c1.Sync(ctx)) + + // 02. attach and initialize document with new fields and if key already exists, it will be discarded + doc2 := document.New(helper.TestDocKey(t)) + assert.NoError(t, c2.Attach(ctx, doc2, client.WithInitialRoot(map[string]any{ + "counter": json.NewCounter(1, crdt.LongCnt), + "content": map[string]any{ + "x": 2, + "y": 2, + }, + "new": map[string]any{ + "k": "v", + }, + }))) + assert.True(t, doc2.IsAttached()) + assert.Equal(t, `{"content":{"x":1,"y":1},"counter":0,"new":{"k":"v"}}`, doc2.Marshal()) + }) + + t.Run("attach with InitialRoot after key deletion test", func(t *testing.T) { + ctx := context.Background() + doc1 := document.New(helper.TestDocKey(t)) + + // 01. client1 attach with initialRoot + assert.NoError(t, c1.Attach(ctx, doc1, client.WithInitialRoot(map[string]any{ + "counter": json.NewCounter(1, crdt.LongCnt), + "content": map[string]any{ + "x": 1, + "y": 1, + }, + }))) + assert.True(t, doc1.IsAttached()) + assert.Equal(t, `{"content":{"x":1,"y":1},"counter":1}`, doc1.Marshal()) + assert.NoError(t, c1.Sync(ctx)) + + // 02. client2 attach with initialRoot and delete elements + doc2 := document.New(helper.TestDocKey(t)) + assert.NoError(t, c2.Attach(ctx, doc2)) + assert.True(t, doc2.IsAttached()) + assert.NoError(t, doc2.Update(func(root *json.Object, p *presence.Presence) error { + root.Delete("content") + root.Delete("counter") + return nil + })) + assert.NoError(t, c2.Sync(ctx)) + + // 03. client3 attach with initialRoot and delete elements + doc3 := document.New(helper.TestDocKey(t)) + assert.NoError(t, c3.Attach(ctx, doc3, client.WithInitialRoot(map[string]any{ + "counter": json.NewCounter(3, crdt.LongCnt), + "content": map[string]any{ + "x": 3, + "y": 3, + }, + }))) + assert.True(t, doc3.IsAttached()) + assert.Equal(t, `{"content":{"x":3,"y":3},"counter":3}`, doc3.Marshal()) + }) + + t.Run("concurrent attach with InitialRoot test", func(t *testing.T) { + ctx := context.Background() + doc1 := document.New(helper.TestDocKey(t)) + + // 01. user1 attach with initialRoot and client doesn't sync + assert.NoError(t, c1.Attach(ctx, doc1, client.WithInitialRoot(map[string]any{ + "first_writer": "user1", + }))) + assert.True(t, doc1.IsAttached()) + assert.Equal(t, `{"first_writer":"user1"}`, doc1.Marshal()) + + // 02. user2 attach with initialRoot and client doesn't sync + doc2 := document.New(helper.TestDocKey(t)) + assert.NoError(t, c2.Attach(ctx, doc2, client.WithInitialRoot(map[string]any{ + "first_writer": "user2", + }))) + assert.True(t, doc2.IsAttached()) + assert.Equal(t, `{"first_writer":"user2"}`, doc2.Marshal()) + + // 03. user1 sync first and user2 seconds + assert.NoError(t, c1.Sync(ctx)) + assert.NoError(t, c2.Sync(ctx)) + + // 04. user1's local document's first_writer was user1 + assert.Equal(t, `{"first_writer":"user1"}`, doc1.Marshal()) + assert.Equal(t, `{"first_writer":"user2"}`, doc2.Marshal()) + + // 05. user1's local document's first_writer is overwritten by user2 + assert.NoError(t, c1.Sync(ctx)) + assert.Equal(t, `{"first_writer":"user2"}`, doc1.Marshal()) + }) + + t.Run("attach with InitialRoot by same key test", func(t *testing.T) { + ctx := context.Background() + doc := document.New(helper.TestDocKey(t)) + + k1 := "key" + k2 := "key" + k3 := "key" + k4 := "key" + k5 := "key" + assert.NoError(t, c1.Attach(ctx, doc, client.WithInitialRoot(map[string]any{ + k1: 1, + k2: 2, + k3: 3, + k4: 4, + k5: 5, + }))) + assert.True(t, doc.IsAttached()) + // The last value is used when the same key is used. + assert.Equal(t, `{"key":5}`, doc.Marshal()) + }) + + t.Run("attach with InitialRoot conflict type test", func(t *testing.T) { + ctx := context.Background() + doc1 := document.New(helper.TestDocKey(t)) + + // 01. attach with initialRoot and set counter + assert.NoError(t, c1.Attach(ctx, doc1, client.WithInitialRoot(map[string]any{ + "k": json.NewCounter(1, crdt.LongCnt), + }))) + assert.True(t, doc1.IsAttached()) + assert.NoError(t, c1.Sync(ctx)) + + // 02. attach with initialRoot and set text + doc2 := document.New(helper.TestDocKey(t)) + assert.NoError(t, c2.Attach(ctx, doc2, client.WithInitialRoot(map[string]any{ + "k": json.NewText(), + }))) + assert.True(t, doc2.IsAttached()) + assert.NoError(t, c2.Sync(ctx)) + + // 03. client2 try to update counter + assert.Panics(t, func() { doc2.Root().GetText("k").Edit(0, 1, "a") }) + }) + + t.Run("attach with initialRoot support type test", func(t *testing.T) { + type ( + Myint int + MyStruct struct { + M Myint + } + t1 struct { + M string + } + T1 struct { + M string + } + T2 struct { + T1 + t1 + M string + } + ) + ctx := context.Background() + nowTime := time.Now() + tests := []struct { + caseName string + input any + expectedJSON string + expectPanic bool + }{ + // supported primitive types + {"nil", nil, `{"k":null}`, false}, + {"int", 1, `{"k":1}`, false}, + {"int32", int32(1), `{"k":1}`, false}, + {"int64", int64(1), `{"k":1}`, false}, + {"float32", float32(1.1), `{"k":1.100000}`, false}, + {"float64", 1.1, `{"k":1.100000}`, false}, + {"string", "hello", `{"k":"hello"}`, false}, + {"bool", true, `{"k":true}`, false}, + {"time", nowTime, `{"k":"` + nowTime.Format(time.RFC3339) + `"}`, false}, + {"Myint", Myint(1), `{"k":1}`, false}, + + // unsupported primitive types + {"int8", int8(1), `{}`, true}, + {"int16", int16(1), `{}`, true}, + {"uint32", uint32(1), `{}`, true}, + {"uint64", uint64(1), `{}`, true}, + + // supported slice, array types + {"int slice", []int{1, 2, 3}, `{"k":[1,2,3]}`, false}, + {"&int slice", &[]int{1, 2, 3}, `{"k":[1,2,3]}`, false}, + {"any slice", []any{nil, 1, 1.0, "hello", true, nowTime, []int{1, 2, 3}}, `{"k":[null,1,1.000000,"hello",true,"` + nowTime.Format(time.RFC3339) + `",[1,2,3]]}`, false}, + {"&any slice", &[]any{nil, 1, 1.0, "hello", true, nowTime, []int{1, 2, 3}}, `{"k":[null,1,1.000000,"hello",true,"` + nowTime.Format(time.RFC3339) + `",[1,2,3]]}`, false}, + {"int array", [3]int{1, 2, 3}, `{"k":[1,2,3]}`, false}, + {"&int array", &[3]int{1, 2, 3}, `{"k":[1,2,3]}`, false}, + {"string array", [3]string{"a", "b", "c"}, `{"k":["a","b","c"]}`, false}, + {"&string array", &[3]string{"a", "b", "c"}, `{"k":["a","b","c"]}`, false}, + {"any array", [7]any{nil, 1, 1.0, "hello", true, nowTime, []int{1, 2, 3}}, `{"k":[null,1,1.000000,"hello",true,"` + nowTime.Format(time.RFC3339) + `",[1,2,3]]}`, false}, + {"&any array", &[7]any{nil, 1, 1.0, "hello", true, nowTime, []int{1, 2, 3}}, `{"k":[null,1,1.000000,"hello",true,"` + nowTime.Format(time.RFC3339) + `",[1,2,3]]}`, false}, + + // supported map types + {"string:any map", map[string]any{"a": nil, "b": 1, "c": 1.0, "d": "hello", "e": true, "f": nowTime, "g": []int{1, 2, 3}}, `{"k":{"a":null,"b":1,"c":1.000000,"d":"hello","e":true,"f":"` + nowTime.Format(time.RFC3339) + `","g":[1,2,3]}}`, false}, + {"&string:any map", &map[string]any{"a": nil, "b": 1, "c": 1.0, "d": "hello", "e": true, "f": nowTime, "g": []int{1, 2, 3}}, `{"k":{"a":null,"b":1,"c":1.000000,"d":"hello","e":true,"f":"` + nowTime.Format(time.RFC3339) + `","g":[1,2,3]}}`, false}, + + // unsupported map types + {"int map", map[int]int{1: 1, 2: 2}, `{}`, true}, + {"string map", map[string]string{"a": "a", "b": "b"}, `{}`, true}, + {"int map", map[int]any{1: 1, 2: 2}, `{}`, true}, + + // supported JSON types + {"json.Text", json.NewText(), `{"k":[]}`, false}, + {"*json.Text", *json.NewText(), `{"k":[]}`, false}, + {"json.Tree", json.NewTree(&json.TreeNode{ // 1: tree + Type: "doc", + Children: []json.TreeNode{{ + Type: "p", Children: []json.TreeNode{{Type: "text", Value: "ab"}}, + }}, + }), `{"k":{"type":"doc","children":[{"type":"p","children":[{"type":"text","value":"ab"}]}]}}`, false}, + {"*json.Tree", *json.NewTree(&json.TreeNode{ + Type: "doc", + Children: []json.TreeNode{{ + Type: "p", Children: []json.TreeNode{{Type: "text", Value: "ab"}}, + }}, + }), `{"k":{"type":"doc","children":[{"type":"p","children":[{"type":"text","value":"ab"}]}]}}`, false}, + {"json.Counter", json.NewCounter(1, crdt.LongCnt), `{"k":1}`, false}, + {"*json.Counter", *json.NewCounter(1, crdt.LongCnt), `{"k":1}`, false}, + + // struct types + {"struct", MyStruct{M: 1}, `{"k":{"M":1}}`, false}, + {"struct pointer", &MyStruct{M: 1}, `{"k":{"M":1}}`, false}, + {"struct slice", []MyStruct{{M: 1}, {M: 2}}, `{"k":[{"M":1},{"M":2}]}`, false}, + {"struct array", [2]MyStruct{{M: 1}, {M: 2}}, `{"k":[{"M":1},{"M":2}]}`, false}, + {"anonymous struct", struct{ M string }{M: "hello"}, `{"k":{"M":"hello"}}`, false}, + {"anonymous struct pointer", &struct{ M string }{M: "hello"}, `{"k":{"M":"hello"}}`, false}, + {"anonymous struct slice", []struct{ M string }{{M: "a"}, {M: "b"}}, `{"k":[{"M":"a"},{"M":"b"}]}`, false}, + {"anonymous struct array", [2]struct{ M string }{{M: "a"}, {M: "b"}}, `{"k":[{"M":"a"},{"M":"b"}]}`, false}, + {"struct with embedded struct", T2{T1: T1{M: "a"}, t1: t1{M: "b"}, M: "c"}, `{"k":{"M":"c","T1":{"M":"a"}}}`, false}, + {"strut with unexported field", struct { + t int + s string + }{t: 1, s: "hello"}, `{"k":{}}`, false}, + {"strut with unexported field pointer", &struct { + t int + s string + }{t: 1, s: "hello"}, `{"k":{}}`, false}, + {"struct with slice", struct{ M []int }{M: []int{1, 2, 3}}, `{"k":{"M":[1,2,3]}}`, false}, + {"struct with slice pointer", &struct{ M []int }{M: []int{1, 2, 3}}, `{"k":{"M":[1,2,3]}}`, false}, + {"struct with array", struct{ M [3]int }{M: [3]int{1, 2, 3}}, `{"k":{"M":[1,2,3]}}`, false}, + {"struct with array pointer", &struct{ M [3]int }{M: [3]int{1, 2, 3}}, `{"k":{"M":[1,2,3]}}`, false}, + {"struct with struct", struct{ M MyStruct }{M: MyStruct{M: 1}}, `{"k":{"M":{"M":1}}}`, false}, + {"struct with struct pointer", &struct{ M MyStruct }{M: MyStruct{M: 1}}, `{"k":{"M":{"M":1}}}`, false}, + {"struct with json types", struct { + T json.Text + C json.Counter + Tree json.Tree + }{T: *json.NewText(), C: *json.NewCounter(1, crdt.LongCnt), Tree: *json.NewTree(&json.TreeNode{ + Type: "doc", + Children: []json.TreeNode{{ + Type: "p", Children: []json.TreeNode{{Type: "text", Value: "ab"}}, + }}, + })}, `{"k":{"C":1,"T":[],"Tree":{"type":"doc","children":[{"type":"p","children":[{"type":"text","value":"ab"}]}]}}}`, false}, + + // unsupported struct types + {"struct with unsupported map", struct{ M map[string]int }{M: map[string]int{"a": 1, "b": 2}}, `{}`, true}, + {"struct with unsupported primitive type", struct{ M int8 }{M: 1}, `{}`, true}, + + {"func", func(a int, b int) int { return a + b }, `{}`, true}, + } + for _, tt := range tests { + t.Run(tt.caseName, func(t *testing.T) { + doc := document.New(helper.TestDocKey(t)) + val := func() { + assert.NoError(t, c1.Attach(ctx, doc, client.WithInitialRoot(map[string]any{ + "k": tt.input, + }))) + } + if tt.expectPanic { + assert.PanicsWithValue(t, "unsupported type", val) + } else { + assert.NotPanics(t, val) + } + assert.Equal(t, tt.expectedJSON, doc.Marshal()) + }) + } + }) +} diff --git a/test/integration/health_test.go b/test/integration/health_test.go index 6ee176de5..02e5fdffc 100644 --- a/test/integration/health_test.go +++ b/test/integration/health_test.go @@ -20,16 +20,26 @@ package integration import ( "context" + "encoding/json" + "net/http" "testing" + "connectrpc.com/grpchealth" "github.com/stretchr/testify/assert" + "github.com/yorkie-team/yorkie/api/yorkie/v1/v1connect" + "github.com/yorkie-team/yorkie/server/rpc/httphealth" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" healthpb "google.golang.org/grpc/health/grpc_health_v1" ) -func TestHealthCheck(t *testing.T) { - // use gRPC health check +var services = []string{ + grpchealth.HealthV1ServiceName, + v1connect.YorkieServiceName, + v1connect.AdminServiceName, +} + +func TestRPCHealthCheck(t *testing.T) { conn, err := grpc.Dial( defaultServer.RPCAddr(), grpc.WithTransportCredentials(insecure.NewCredentials()), @@ -38,9 +48,114 @@ func TestHealthCheck(t *testing.T) { defer func() { assert.NoError(t, conn.Close()) }() - cli := healthpb.NewHealthClient(conn) - resp, err := cli.Check(context.Background(), &healthpb.HealthCheckRequest{}) - assert.NoError(t, err) - assert.Equal(t, resp.Status, healthpb.HealthCheckResponse_SERVING) + + // check default service + t.Run("Service: default", func(t *testing.T) { + resp, err := cli.Check(context.Background(), &healthpb.HealthCheckRequest{}) + assert.NoError(t, err) + assert.Equal(t, healthpb.HealthCheckResponse_SERVING, resp.Status) + }) + + // check all services + for _, s := range services { + service := s + t.Run("Service: "+service, func(t *testing.T) { + resp, err := cli.Check(context.Background(), &healthpb.HealthCheckRequest{ + Service: service, + }) + assert.NoError(t, err) + assert.Equal(t, healthpb.HealthCheckResponse_SERVING, resp.Status) + }) + } + + // check unknown service + t.Run("Service: unknown", func(t *testing.T) { + _, err := cli.Check(context.Background(), &healthpb.HealthCheckRequest{ + Service: "unknown", + }) + assert.Error(t, err) + }) +} + +func TestHTTPGETHealthCheck(t *testing.T) { + // check default service + t.Run("Service: default", func(t *testing.T) { + resp, err := http.Get("http://" + defaultServer.RPCAddr() + httphealth.HealthV1ServiceName) + assert.NoError(t, err) + defer func() { + assert.NoError(t, resp.Body.Close()) + }() + assert.Equal(t, http.StatusOK, resp.StatusCode) + + var healthResp httphealth.CheckResponse + err = json.NewDecoder(resp.Body).Decode(&healthResp) + assert.NoError(t, err) + assert.Equal(t, grpchealth.StatusServing.String(), healthResp.Status) + }) + + // check all services + for _, s := range services { + service := s + t.Run("Service: "+service, func(t *testing.T) { + url := "http://" + defaultServer.RPCAddr() + httphealth.HealthV1ServiceName + "?service=" + service + resp, err := http.Get(url) + assert.NoError(t, err) + defer func() { + assert.NoError(t, resp.Body.Close()) + }() + assert.Equal(t, http.StatusOK, resp.StatusCode) + + var healthResp httphealth.CheckResponse + err = json.NewDecoder(resp.Body).Decode(&healthResp) + assert.NoError(t, err) + assert.Equal(t, grpchealth.StatusServing.String(), healthResp.Status) + }) + } + + // check unknown service + t.Run("Service: unknown", func(t *testing.T) { + resp, err := http.Get("http://" + defaultServer.RPCAddr() + httphealth.HealthV1ServiceName + "?service=unknown") + assert.NoError(t, err) + defer func() { + assert.NoError(t, resp.Body.Close()) + }() + assert.Equal(t, http.StatusNotFound, resp.StatusCode) + }) +} + +func TestHTTPHEADHealthCheck(t *testing.T) { + // check default service + t.Run("Service: default", func(t *testing.T) { + resp, err := http.Head("http://" + defaultServer.RPCAddr() + httphealth.HealthV1ServiceName) + assert.NoError(t, err) + defer func() { + assert.NoError(t, resp.Body.Close()) + }() + assert.Equal(t, http.StatusOK, resp.StatusCode) + }) + + // check all services + for _, s := range services { + service := s + t.Run("Service: "+service, func(t *testing.T) { + url := "http://" + defaultServer.RPCAddr() + httphealth.HealthV1ServiceName + "?service=" + service + resp, err := http.Head(url) + assert.NoError(t, err) + defer func() { + assert.NoError(t, resp.Body.Close()) + }() + assert.Equal(t, http.StatusOK, resp.StatusCode) + }) + } + + // check unknown service + t.Run("Service: unknown", func(t *testing.T) { + resp, err := http.Head("http://" + defaultServer.RPCAddr() + httphealth.HealthV1ServiceName + "?service=unknown") + assert.NoError(t, err) + defer func() { + assert.NoError(t, resp.Body.Close()) + }() + assert.Equal(t, http.StatusNotFound, resp.StatusCode) + }) } diff --git a/test/integration/housekeeping_test.go b/test/integration/housekeeping_test.go index 9b56d916d..add1a9a93 100644 --- a/test/integration/housekeeping_test.go +++ b/test/integration/housekeeping_test.go @@ -25,18 +25,17 @@ import ( "log" "sort" "testing" - gotime "time" - monkey "github.com/undefinedlabs/go-mpatch" - "github.com/stretchr/testify/assert" + monkey "github.com/undefinedlabs/go-mpatch" "github.com/yorkie-team/yorkie/api/types" + "github.com/yorkie-team/yorkie/server/backend" "github.com/yorkie-team/yorkie/server/backend/database" "github.com/yorkie-team/yorkie/server/backend/database/mongo" - "github.com/yorkie-team/yorkie/server/backend/housekeeping" - "github.com/yorkie-team/yorkie/server/backend/sync/memory" + "github.com/yorkie-team/yorkie/server/clients" + "github.com/yorkie-team/yorkie/server/profiling/prometheus" "github.com/yorkie-team/yorkie/test/helper" ) @@ -46,41 +45,49 @@ const ( clientDeactivateThreshold = "23h" ) -func setupTest(t *testing.T) *mongo.Client { - config := &mongo.Config{ +func setupBackend(t *testing.T) *backend.Backend { + conf := helper.TestConfig() + conf.Backend.UseDefaultProject = false + conf.Mongo = &mongo.Config{ ConnectionTimeout: "5s", ConnectionURI: "mongodb://localhost:27017", YorkieDatabase: helper.TestDBName() + "-integration", PingTimeout: "5s", } - assert.NoError(t, config.Validate()) - cli, err := mongo.Dial(config) + metrics, err := prometheus.NewMetrics() + assert.NoError(t, err) + + be, err := backend.New( + conf.Backend, + conf.Mongo, + conf.Housekeeping, + metrics, + ) assert.NoError(t, err) - return cli + return be } func TestHousekeeping(t *testing.T) { - config := helper.TestConfig() - db := setupTest(t) + be := setupBackend(t) + defer func() { + assert.NoError(t, be.Shutdown()) + }() - projects := createProjects(t, db) - - coordinator := memory.NewCoordinator(nil) - - h, err := housekeeping.New(config.Housekeeping, db, coordinator) - assert.NoError(t, err) + projects := createProjects(t, be.DB) t.Run("FindDeactivateCandidates return lastProjectID test", func(t *testing.T) { ctx := context.Background() fetchSize := 3 - lastProjectID := database.DefaultProjectID + var err error + lastProjectID := database.DefaultProjectID for i := 0; i < len(projects)/fetchSize; i++ { - lastProjectID, _, err = h.FindDeactivateCandidates( + lastProjectID, _, err = clients.FindDeactivateCandidates( ctx, + be, 0, fetchSize, lastProjectID, @@ -89,8 +96,9 @@ func TestHousekeeping(t *testing.T) { assert.Equal(t, projects[((i+1)*fetchSize)-1].ID, lastProjectID) } - lastProjectID, _, err = h.FindDeactivateCandidates( + lastProjectID, _, err = clients.FindDeactivateCandidates( ctx, + be, 0, fetchSize, lastProjectID, @@ -107,20 +115,20 @@ func TestHousekeeping(t *testing.T) { if err != nil { log.Fatal(err) } - clientA, err := db.ActivateClient(ctx, projects[0].ID, fmt.Sprintf("%s-A", t.Name())) + clientA, err := be.DB.ActivateClient(ctx, projects[0].ID, fmt.Sprintf("%s-A", t.Name())) assert.NoError(t, err) - clientB, err := db.ActivateClient(ctx, projects[0].ID, fmt.Sprintf("%s-B", t.Name())) + clientB, err := be.DB.ActivateClient(ctx, projects[0].ID, fmt.Sprintf("%s-B", t.Name())) assert.NoError(t, err) - err = patch.Unpatch() - if err != nil { + if err = patch.Unpatch(); err != nil { log.Fatal(err) } - clientC, err := db.ActivateClient(ctx, projects[0].ID, fmt.Sprintf("%s-C", t.Name())) + clientC, err := be.DB.ActivateClient(ctx, projects[0].ID, fmt.Sprintf("%s-C", t.Name())) assert.NoError(t, err) - _, candidates, err := h.FindDeactivateCandidates( + _, candidates, err := clients.FindDeactivateCandidates( ctx, + be, 10, 10, database.DefaultProjectID, @@ -134,7 +142,7 @@ func TestHousekeeping(t *testing.T) { }) } -func createProjects(t *testing.T, db *mongo.Client) []*database.ProjectInfo { +func createProjects(t *testing.T, db database.Database) []*database.ProjectInfo { t.Helper() ctx := context.Background() diff --git a/test/integration/main_test.go b/test/integration/main_test.go index e63be3137..d966cf9cf 100644 --- a/test/integration/main_test.go +++ b/test/integration/main_test.go @@ -34,6 +34,11 @@ import ( "github.com/yorkie-team/yorkie/test/helper" ) +type testResult struct { + flag bool + resultDesc string +} + type clientAndDocPair struct { cli *client.Client doc *document.Document diff --git a/test/integration/retention_test.go b/test/integration/retention_test.go index 5864a9d3c..a8662bc98 100644 --- a/test/integration/retention_test.go +++ b/test/integration/retention_test.go @@ -44,7 +44,11 @@ func TestRetention(t *testing.T) { patch, err := monkey.PatchInstanceMethodByName( reflect.TypeOf(b), "AttachGoroutine", - func(_ *background.Background, f func(c context.Context)) { + func( + _ *background.Background, + f func(c context.Context), + _ string, + ) { f(context.Background()) }, ) diff --git a/test/integration/snapshot_test.go b/test/integration/snapshot_test.go index 7e3cc3a73..25ea67589 100644 --- a/test/integration/snapshot_test.go +++ b/test/integration/snapshot_test.go @@ -40,7 +40,11 @@ func TestSnapshot(t *testing.T) { patch, err := monkey.PatchInstanceMethodByName( reflect.TypeOf(b), "AttachGoroutine", - func(_ *background.Background, f func(c context.Context)) { + func( + _ *background.Background, + f func(c context.Context), + _ string, + ) { f(context.Background()) }, )