From 1caea9ab961797d1d75a9f3cf8fbeffdc1c48985 Mon Sep 17 00:00:00 2001 From: withchao <993506633@qq.com> Date: Tue, 27 Aug 2024 14:43:24 +0800 Subject: [PATCH 01/36] fix: user search fields --- pkg/common/db/model/chat/attribute.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/common/db/model/chat/attribute.go b/pkg/common/db/model/chat/attribute.go index 81e56f717..9b83b2df3 100644 --- a/pkg/common/db/model/chat/attribute.go +++ b/pkg/common/db/model/chat/attribute.go @@ -136,10 +136,10 @@ func (o *Attribute) SearchNormalUser(ctx context.Context, keyword string, forbid } if keyword != "" { filter["$or"] = []bson.M{ - //{"user_id": bson.M{"$regex": keyword, "$options": "i"}}, - //{"account": bson.M{"$regex": keyword, "$options": "i"}}, + {"user_id": bson.M{"$regex": keyword, "$options": "i"}}, + {"account": bson.M{"$regex": keyword, "$options": "i"}}, {"nickname": bson.M{"$regex": keyword, "$options": "i"}}, - //{"phone_number": bson.M{"$regex": keyword, "$options": "i"}}, + {"phone_number": bson.M{"$regex": keyword, "$options": "i"}}, } } return mongoutil.FindPage[*chat.Attribute](ctx, o.coll, filter, pagination) From f1ae650f560a43f786a5f6e73f5184add35a9ddd Mon Sep 17 00:00:00 2001 From: OpenIM-Gordon <46924906+FGadvancer@users.noreply.github.com> Date: Mon, 14 Oct 2024 15:31:06 +0800 Subject: [PATCH 02/36] merge: update release-v1.8 with main changes. (#581) * fix: user search fields * fix: reset UserPassword in admin. (#572) * update dockerfile contents. * update field. * fix: reset UserPassword in admin. * refactor: improve github workflows. (#573) * update dockerfile contents. * update field. * refactor: improve github workflows. * remove en * feat: update RegisterUser use adminToken. (#574) * update dockerfile contents. * update field. * feat: update RegisterUser use adminToken. * refactor: update token logic. (#575) * update dockerfile contents. * update field. * refactor: update token logic. * remove unused ci. * fix: mobile phone number, email address, account modification verification (#578) * update gomake version * update gomake version * update version * fix: mobile phone number, email address, account modification verification * fix: assign livekit node ip (#570) * WIP:feat: update update version file workflows. (#576) * update dockerfile contents. * update field. * feat: update update version file workflows. * feat: add version file. * Update version * update log module. * refactor: update adminToken (#580) * update dockerfile contents. * update field. * refactor: update adminToken --------- Co-authored-by: withchao <993506633@qq.com> Co-authored-by: Monet Lee Co-authored-by: chao <48119764+withchao@users.noreply.github.com> Co-authored-by: blooming <37789413+Bloomingg@users.noreply.github.com> --- .github/.codecov.yml | 1 - .github/code-language-detector.yml | 7 - .github/labels.yml | 43 ----- .github/sync-release.yml | 16 -- .github/weekly-digest.yml | 21 --- .github/workflows/auto-assign-issue.yml | 28 +-- .github/workflows/auto-gh-pr.yml | 60 ------ .github/workflows/auto-invite-comment.yml | 39 ++++ .github/workflows/auto-tag.yml | 52 ------ .github/workflows/build-docker-image.yml | 14 -- .github/workflows/chatci.yml | 19 +- .github/workflows/check-coverage.yml | 14 -- .github/workflows/cla-assistant.yml | 40 ++++ .github/workflows/cla.yml | 62 ------- .github/workflows/codeql-analysis.yml | 103 +++++------ .github/workflows/comment-check.yml | 51 ++++++ .github/workflows/depsreview.yaml | 18 -- .github/workflows/gosec.yml | 14 -- .github/workflows/help-comment-issue.yml | 21 +-- .github/workflows/issue-translator.yml | 19 ++ .github/workflows/language-check.yml | 13 -- .github/workflows/project-progress.yml | 36 ---- .github/workflows/pull-request.yml | 115 ------------ .github/workflows/release.yml | 14 -- .github/workflows/reopen-issue.yml | 78 ++++++++ .../update-version-file-on-release.yml | 84 +++++++++ HOW_TO_SETUP_LIVEKIT_SERVER.md | 4 +- config/log.yml | 2 + go.mod | 5 +- go.sum | 8 +- internal/api/admin/admin.go | 46 +++-- internal/api/chat/chat.go | 15 +- internal/rpc/chat/login.go | 5 +- internal/rpc/chat/update.go | 6 +- internal/rpc/chat/user.go | 124 +++++++++---- livekit/livekit.yaml | 2 +- pkg/common/cmd/root.go | 10 +- pkg/common/config/config.go | 2 + pkg/common/imapi/api.go | 9 +- pkg/common/imapi/caller.go | 33 ++-- pkg/protocol/sdkws/sdkws.proto | 173 ++++++++---------- tools/check-component/main.go | 3 +- version/version/version | 1 + version/version/version.go | 6 + 44 files changed, 653 insertions(+), 783 deletions(-) delete mode 100644 .github/code-language-detector.yml delete mode 100644 .github/labels.yml delete mode 100644 .github/weekly-digest.yml delete mode 100644 .github/workflows/auto-gh-pr.yml create mode 100644 .github/workflows/auto-invite-comment.yml delete mode 100644 .github/workflows/auto-tag.yml create mode 100644 .github/workflows/cla-assistant.yml delete mode 100644 .github/workflows/cla.yml create mode 100644 .github/workflows/comment-check.yml delete mode 100644 .github/workflows/depsreview.yaml create mode 100644 .github/workflows/issue-translator.yml delete mode 100644 .github/workflows/language-check.yml delete mode 100644 .github/workflows/project-progress.yml delete mode 100644 .github/workflows/pull-request.yml create mode 100644 .github/workflows/reopen-issue.yml create mode 100644 .github/workflows/update-version-file-on-release.yml create mode 100644 version/version/version create mode 100644 version/version/version.go diff --git a/.github/.codecov.yml b/.github/.codecov.yml index 9e262e0e3..25b77e528 100644 --- a/.github/.codecov.yml +++ b/.github/.codecov.yml @@ -11,7 +11,6 @@ # 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. - coverage: status: project: diff --git a/.github/code-language-detector.yml b/.github/code-language-detector.yml deleted file mode 100644 index 6e5386249..000000000 --- a/.github/code-language-detector.yml +++ /dev/null @@ -1,7 +0,0 @@ -directory: ./ -file_types: - - .go - - .yaml - - .yml -languages: - - Chinese diff --git a/.github/labels.yml b/.github/labels.yml deleted file mode 100644 index b85a824b4..000000000 --- a/.github/labels.yml +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright © 2023 OpenIM. 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. - -# Refer to Kubernetes for size/* Settings -# https://github.com/Kubernetes/Kubernetes -XS: - name: size/XS - lines: 0 - color: 3CBF00 -S: - name: size/S - lines: 10 - color: 5D9801 -M: - name: size/M - lines: 30 - color: 7F7203 -L: - name: size/L - lines: 100 - color: A14C05 -XL: - name: size/XL - lines: 500 - color: C32607 -XXL: - name: size/XXL - lines: 1000 - color: E50009 - comment: | - # Whoa! Easy there, Partner! - This PR is too big. Please break it up into smaller PRs. \ No newline at end of file diff --git a/.github/sync-release.yml b/.github/sync-release.yml index b8c27976d..1472ba58b 100644 --- a/.github/sync-release.yml +++ b/.github/sync-release.yml @@ -1,19 +1,3 @@ -# Copyright © 2023 OpenIM. 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. - -# https://github.com/BetaHuhn/repo-file-sync-action -# Synchronization for the.github repository openim-sigs/openim-docker: - source: ./config dest: ./openim-chat/release/config diff --git a/.github/weekly-digest.yml b/.github/weekly-digest.yml deleted file mode 100644 index fb3614ad8..000000000 --- a/.github/weekly-digest.yml +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright © 2023 OpenIM. 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. - -# https://github.com/apps/weekly-digest/installations/new -publishDay: sun -canPublishIssues: true -canPublishPullRequests: true -canPublishContributors: true -canPublishStargazers: true -canPublishCommits: true \ No newline at end of file diff --git a/.github/workflows/auto-assign-issue.yml b/.github/workflows/auto-assign-issue.yml index d87a571dc..320174d8c 100644 --- a/.github/workflows/auto-assign-issue.yml +++ b/.github/workflows/auto-assign-issue.yml @@ -1,17 +1,3 @@ -# Copyright © 2023 OpenIM open source community. 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. - name: Assign issue to comment author on: issue_comment: @@ -20,24 +6,24 @@ jobs: assign-issue: if: | contains(github.event.comment.body, '/assign') || contains(github.event.comment.body, '/accept') && - !contains(github.event.comment.user.login, 'openimbot') && - !contains(github.event.comment.user.login, 'kubbot') + !contains(github.event.comment.user.login, 'openim-robot') runs-on: ubuntu-latest permissions: issues: write steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Assign the issue run: | export LETASE_MILESTONES=$(curl 'https://api.github.com/repos/$OWNER/$PEPO/milestones' | jq -r 'last(.[]).title') gh issue edit ${{ github.event.issue.number }} --add-assignee "${{ github.event.comment.user.login }}" - gh issue edit ${{ github.event.issue.number }} --add-label "triage/accepted" - gh issue edit ${{ github.event.issue.number }} --milestone "$LETASE_MILESTONES" + gh issue edit ${{ github.event.issue.number }} --add-label "accepted" gh issue comment $ISSUE --body "@${{ github.event.comment.user.login }} Glad to see you accepted this issue🤲, this issue has been assigned to you. I set the milestones for this issue to [$LETASE_MILESTONES](https://github.com/$OWNER/$PEPO/milestones), We are looking forward to your PR!" + + # gh issue edit ${{ github.event.issue.number }} --milestone "$LETASE_MILESTONES" env: - GH_TOKEN: ${{ secrets.REDBOT_GITHUB_TOKEN }} + GH_TOKEN: ${{ secrets.BOT_TOKEN }} ISSUE: ${{ github.event.issue.html_url }} OWNER: ${{ github.repository_owner }} - REPO: ${{ github.event.repository.name }} \ No newline at end of file + REPO: ${{ github.event.repository.name }} diff --git a/.github/workflows/auto-gh-pr.yml b/.github/workflows/auto-gh-pr.yml deleted file mode 100644 index 0913655ca..000000000 --- a/.github/workflows/auto-gh-pr.yml +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -name: Auto PR to release - -on: - pull_request: - # types: - # - closed - issue_comment: - types: [created] - pull_request_review_comment: - types: [created] - -jobs: - create-pr: - runs-on: ubuntu-latest - if: github.event.pull_request.base.ref == 'main' && github.event.pull_request.merged == true - steps: - - name: Check out code - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Create PR to release branch - run: | - ISSUEID=$(gh pr view ${{ github.event.pull_request.number }} --repo $OWNER/$REPO | grep -oP 'Fixes #\K\d+') - echo "===========> $ISSUEID" - ISSUE=$(gh issue view $ISSUEID --repo $OWNER/$REPO --json labels,assignees,milestone,title) - echo "===========> $ISSUE" - - LABELS=$(echo $ISSUE | jq -r '.labels[] | select(.name) | .name' | jq -R -r -s -c 'split("\n")[:-1] | join(",")') - ASSIGNEES=$(echo $ISSUE | jq -r '.assignees[] | select(.login) | .login' | jq -R -s -c 'split("\n")[:-1] | join(",")') - MILESTONE=$(echo $ISSUE | jq -r '.milestone | select(.title) | .title') - TITLE=$(echo $ISSUE | jq -r '.title') - - gh pr edit ${{ github.event.pull_request.number }} --repo $OWNER/$REPO --add-label "$LABELS" --add-assignee "$ASSIGNEES" --milestone "$MILESTONE" - - # git checkout -b bot/merge-to-release-$ISSUEID - # git push origin bot/merge-to-release-$ISSUEID - # gh pr create --base release --head bot/merge-to-release-$ISSUEID --title "Merge main to release" --body "" - # gh pr create --base main --head feat/auto-release-pr-624 --title "The bug is fixed" --body "$x" --repo OpenIMSDK/Open-IM-Server --reviewer "cubxxw" - continue-on-error: true - env: - GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }} - GH_TOKEN: ${{ github.token }} - ISSUE: ${{ github.event.issue.html_url }} - OWNER: ${{ github.repository_owner }} - REPO: ${{ github.event.repository.name }} diff --git a/.github/workflows/auto-invite-comment.yml b/.github/workflows/auto-invite-comment.yml new file mode 100644 index 000000000..76fbcdfd3 --- /dev/null +++ b/.github/workflows/auto-invite-comment.yml @@ -0,0 +1,39 @@ +name: Invite users to join OpenIM Community. +on: + issue_comment: + types: + - created +jobs: + issue_comment: + name: Invite users to join OpenIM Community + if: ${{ github.event.comment.body == '/invite' || github.event.comment.body == '/close' || github.event.comment.body == '/comment' }} + runs-on: ubuntu-latest + permissions: + issues: write + steps: + + - name: Invite user to join OpenIM Community + uses: peter-evans/create-or-update-comment@v4 + with: + token: ${{ secrets.BOT_GITHUB_TOKEN }} + issue-number: ${{ github.event.issue.number }} + body: | + We value close connections with our users, developers, and contributors here at Open-IM-Server. With a large community and maintainer team, we're always here to help and support you. Whether you're looking to join our community or have any questions or suggestions, we welcome you to get in touch with us. + + Our most recommended way to get in touch is through [Slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q). Even if you're in China, Slack is usually not blocked by firewalls, making it an easy way to connect with us. Our Slack community is the ideal place to discuss and share ideas and suggestions with other users and developers of Open-IM-Server. You can ask technical questions, seek help, or share your experiences with other users of Open-IM-Server. + + In addition to Slack, we also offer the following ways to get in touch: + + + We also have Slack channels for you to communicate and discuss. To join, visit https://slack.com/ and join our [👀 Open-IM-Server slack](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) team channel. + + Get in touch with us on [Gmail](https://mail.google.com/mail/u/0/?fs=1&tf=cm&to=winxu81@gmail.com). If you have any questions or issues that need resolving, or any suggestions and feedback for our open source projects, please feel free to contact us via email. + + Read our [blog](https://doc.rentsoft.cn/). Our blog is a great place to stay up-to-date with Open-IM-Server projects and trends. On the blog, we share our latest developments, tech trends, and other interesting information. + + Add [Wechat](https://github.com/OpenIMSDK/OpenIM-Docs/blob/main/docs/images/WechatIMG20.jpeg) and indicate that you are a user or developer of Open-IM-Server. We will process your request as soon as possible. + + # - name: Close Issue + # uses: peter-evans/close-issue@v3 + # with: + # token: ${{ secrets.BOT_GITHUB_TOKEN }} + # issue-number: ${{ github.event.issue.number }} + # comment: 🤖 Auto-closing issue, if you still need help please reopen the issue or ask for help in the community above + # labels: | + # accepted \ No newline at end of file diff --git a/.github/workflows/auto-tag.yml b/.github/workflows/auto-tag.yml deleted file mode 100644 index e50ab4ed6..000000000 --- a/.github/workflows/auto-tag.yml +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -name: Create Tag - -on: - issue_comment: - types: [created] - pull_request_review_comment: - types: [created] - -jobs: - create_tag: - runs-on: ubuntu-latest - if: startsWith(github.event.comment.body, '/create tag') - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Validate version number and get comment - id: validate - run: | - COMMENT="${{ github.event.comment.body }}" - VERSION=$(echo $COMMENT | cut -d ' ' -f 3) - TAG_COMMENT=$(echo $COMMENT | cut -d '"' -f 2) - if [[ $VERSION =~ ^v([0-9]+\.){2}[0-9]+$ ]]; then - echo "version=$VERSION" >> $GITHUB_STATE - echo "tag_comment=$TAG_COMMENT" >> $GITHUB_STATE - else - echo "Invalid version number." - exit 1 - fi - - - name: Create a new tag - env: - GH_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }} - run: | - source $GITHUB_STATE - git tag -a $VERSION -m "$tag_comment" - git push origin $VERSION - echo "tag_created=$VERSION" >> $GITHUB_OUTPUT diff --git a/.github/workflows/build-docker-image.yml b/.github/workflows/build-docker-image.yml index db154c467..64d5d0c5c 100644 --- a/.github/workflows/build-docker-image.yml +++ b/.github/workflows/build-docker-image.yml @@ -1,17 +1,3 @@ -# Copyright © 2023 OpenIM open source community. 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. - name: Publish Docker image on: diff --git a/.github/workflows/chatci.yml b/.github/workflows/chatci.yml index 6f97293e4..e6c1b7a83 100644 --- a/.github/workflows/chatci.yml +++ b/.github/workflows/chatci.yml @@ -1,16 +1,3 @@ -# Copyright © 2023 OpenIM open source community. 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. name: OpenIM CI Auto Build on: @@ -45,11 +32,11 @@ jobs: permissions: contents: write pull-requests: write - environment: - name: openim + # environment: + # name: openim strategy: matrix: - arch: [arm64, armv7, amd64] + arch: [amd64] steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/check-coverage.yml b/.github/workflows/check-coverage.yml index 7080ef7be..8c8d44185 100644 --- a/.github/workflows/check-coverage.yml +++ b/.github/workflows/check-coverage.yml @@ -1,17 +1,3 @@ -# Copyright © 2023 OpenIM open source community. 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. - name: Check-Coverage on: diff --git a/.github/workflows/cla-assistant.yml b/.github/workflows/cla-assistant.yml new file mode 100644 index 000000000..4aaa4e25a --- /dev/null +++ b/.github/workflows/cla-assistant.yml @@ -0,0 +1,40 @@ +name: CLA Assistant +on: + issue_comment: + types: [created] + pull_request_target: + types: [opened,closed,synchronize] + +# explicitly configure permissions, in case your GITHUB_TOKEN workflow permissions are set to read-only in repository settings +permissions: + actions: write + contents: write # this can be 'read' if the signatures are in remote repository + pull-requests: write + statuses: write + +jobs: + CLA-Assistant: + runs-on: ubuntu-latest + steps: + - name: "CLA Assistant" + if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target' + uses: contributor-assistant/github-action@v2.4.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PERSONAL_ACCESS_TOKEN: ${{ secrets.BOT_TOKEN }} + with: + path-to-signatures: 'signatures/cla.json' + path-to-document: 'https://github.com/OpenIM-Robot/cla/blob/main/README.md' # e.g. a CLA or a DCO document + branch: 'main' + allowlist: 'bot*,*bot,OpenIM-Robot' + + # the followings are the optional inputs - If the optional inputs are not given, then default values will be taken + remote-organization-name: OpenIM-Robot + remote-repository-name: cla + create-file-commit-message: 'Creating file for storing CLA Signatures' + # signed-commit-message: '$contributorName has signed the CLA in $owner/$repo#$pullRequestNo' + custom-notsigned-prcomment: '💕 Thank you for your contribution and please kindly read and sign our CLA. [CLA Docs](https://github.com/OpenIM-Robot/cla/blob/main/README.md)' + custom-pr-sign-comment: 'I have read the CLA Document and I hereby sign the CLA' + custom-allsigned-prcomment: '🤖 All Contributors have signed the [CLA](https://github.com/OpenIM-Robot/cla/blob/main/README.md).
The signed information is recorded [**here**](https://github.com/OpenIM-Robot/cla/blob/main/signatures/cla.json)' + #lock-pullrequest-aftermerge: false - if you don't want this bot to automatically lock the pull request after merging (default - true) + #use-dco-flag: true - If you are using DCO instead of CLA \ No newline at end of file diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml deleted file mode 100644 index 3f658284a..000000000 --- a/.github/workflows/cla.yml +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -name: "OpenIM CLA Assistant" -on: - issue_comment: - types: [created] - pull_request_target: - types: [opened,closed,synchronize] - -# explicitly configure permissions, in case your GITHUB_TOKEN workflow permissions are set to read-only in repository settings -permissions: - actions: write - contents: write - pull-requests: write - statuses: write - -env: - # Define Open-IM-Server variables here - OPEN_IM_SERVER_REMOTE_ORGANIZATION: openim-sigs - REMOTE_REPOSITORY: cla - OPEN_IM_SERVER_CLA_DOCUMENT: https://github.com/openim-sigs/cla/blob/main/README.md - OPEN_IM_SERVER_SIGNATURES_PATH: signatures/${{ github.event.repository.name }}/cla.json - - OPEN_IM_SERVER_ALLOWLIST: kubbot,bot* - -jobs: - CLAAssistant: - runs-on: ubuntu-latest - steps: - - name: "CLA Assistant" - if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target' - uses: contributor-assistant/github-action@v2.3.0 - env: - GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }} - PERSONAL_ACCESS_TOKEN: ${{ secrets.REDBOT_GITHUB_TOKEN }} - with: - path-to-signatures: ${{ env.OPEN_IM_SERVER_SIGNATURES_PATH }} - path-to-document: ${{ env.OPEN_IM_SERVER_CLA_DOCUMENT }} - branch: 'main' - allowlist: ${{ env.OPEN_IM_SERVER_ALLOWLIST }} - - remote-organization-name: ${{ env.OPEN_IM_SERVER_REMOTE_ORGANIZATION }} - remote-repository-name: ${{ env.REMOTE_REPOSITORY }} - - create-file-commit-message: '📚 Docs: Creating file for storing ${{ github.event.repository.name }} CLA Signatures' - custom-notsigned-prcomment: '💕 Thank you for your contribution and please kindly read and sign our [🎯https://github.com/openim-sigs/cla/blob/main/README.md](https://github.com/openim-sigs/cla/blob/main/README.md).
If you wish to sign the CRA, **Please copy and comment on the following sentence:**' - custom-pr-sign-comment: 'I have read the CLA Document and I hereby sign the CLA' - custom-allsigned-prcomment: '🤖 All Contributors have signed the [${{ github.event.repository.name }} CLA](https://github.com/openim-sigs/cla/blob/main/README.md).
The signed information is recorded [🤖here](https://github.com/openim-sigs/cla/tree/main/signatures/${{ github.event.repository.name }}/cla.json)' - # lock-pullrequest-aftermerge: false - if you don't want this bot to automatically lock the pull request after merging (default - true) - # use-dco-flag: true - If you are using DCO instead of CLA diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 6233ffcad..fd871e2b5 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,76 +1,67 @@ -# Copyright © 2023 OpenIM open source community. All rights reserved. +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. # -# 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 +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. # -# 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. - +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. -name: "Code Scanning - Action" +name: "CodeQL" on: push: - branches: [main] + branches: [ main ] pull_request: - branches: [main] + # The branches below must be a subset of the branches above + branches: [ main ] schedule: - # ┌───────────── minute (0 - 59) - # │ ┌───────────── hour (0 - 23) - # │ │ ┌───────────── day of the month (1 - 31) - # │ │ │ ┌───────────── month (1 - 12 or JAN-DEC) - # │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT) - # │ │ │ │ │ - # │ │ │ │ │ - # │ │ │ │ │ - # * * * * * - - cron: '30 1 * * 0' + - cron: '18 19 * * 6' jobs: - CodeQL-Build: - # CodeQL runs on ubuntu-latest, windows-latest, and macos-latest + analyze: + name: Analyze runs-on: ubuntu-latest - permissions: - # required for all workflows - security-events: write - - # only required for workflows in private repositories - actions: read - contents: read + strategy: + fail-fast: false + matrix: + language: [ 'go' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] + # Learn more: + # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed steps: - - name: Checkout repository - uses: actions/checkout@v3 + - name: Checkout repository + uses: actions/checkout@v4 - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - # Override language selection by uncommenting this and choosing your languages - # with: - # languages: go, javascript, csharp, python, cpp, java, ruby + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main - # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). - # If this step fails, then you should remove it and run the build manually (see below). - - name: Autobuild - uses: github/codeql-action/autobuild@v2 + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v3 - # ℹ️ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl - # ✏️ If the Autobuild fails above, remove it and uncomment the following - # three lines and modify them (or add more) to build your code if your - # project uses a compiled language + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language - #- run: | - # make bootstrap - # make release + #- run: | + # make bootstrap + # make release - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 \ No newline at end of file + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 \ No newline at end of file diff --git a/.github/workflows/comment-check.yml b/.github/workflows/comment-check.yml new file mode 100644 index 000000000..1609355ed --- /dev/null +++ b/.github/workflows/comment-check.yml @@ -0,0 +1,51 @@ +name: Non-English Comments Check + +on: + pull_request: + branches: + - main + workflow_dispatch: + +jobs: + non-english-comments-check: + runs-on: ubuntu-latest + + env: + # need ignore Dirs + EXCLUDE_DIRS: ".git docs tests scripts assets node_modules build" + # need ignore Files + EXCLUDE_FILES: "*.md *.txt *.html *.css *.min.js *.mdx" + + steps: + - uses: actions/checkout@v4 + + - name: Search for Non-English comments + run: | + set -e + # Define the regex pattern to match Chinese characters + pattern='[\p{Han}]' + + # Process the directories to be excluded + exclude_dirs="" + for dir in $EXCLUDE_DIRS; do + exclude_dirs="$exclude_dirs --exclude-dir=$dir" + done + + # Process the file types to be excluded + exclude_files="" + for file in $EXCLUDE_FILES; do + exclude_files="$exclude_files --exclude=$file" + done + + # Use grep to find all comments containing Non-English characters and save to file + grep -Pnr "$pattern" . $exclude_dirs $exclude_files > non_english_comments.txt || true + + - name: Output non-English comments are found + run: | + if [ -s non_english_comments.txt ]; then + echo "Non-English comments found in the following locations:" + cat non_english_comments.txt + exit 1 # terminate the workflow + else + echo "No Non_English comments found." + fi \ No newline at end of file diff --git a/.github/workflows/depsreview.yaml b/.github/workflows/depsreview.yaml deleted file mode 100644 index c95afb845..000000000 --- a/.github/workflows/depsreview.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright © 2023 KubeCub open source community. All rights reserved. -# Licensed under the MIT License (the "License"); -# you may not use this file except in compliance with the License. - -name: Dependency Review -on: [pull_request] - -permissions: - contents: read - -jobs: - dependency-review: - runs-on: ubuntu-latest - steps: - - name: 'Checkout Repository' - uses: actions/checkout@v3 - - name: 'Dependency Review' - uses: actions/dependency-review-action@v3 \ No newline at end of file diff --git a/.github/workflows/gosec.yml b/.github/workflows/gosec.yml index 708eca4f8..43fba5c0c 100644 --- a/.github/workflows/gosec.yml +++ b/.github/workflows/gosec.yml @@ -1,17 +1,3 @@ -# Copyright © 2023 OpenIM. 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. - name: OpenIM Run Gosec # gosec is a source code security audit tool for the Go language. It performs a static diff --git a/.github/workflows/help-comment-issue.yml b/.github/workflows/help-comment-issue.yml index 755fb035d..bb6367e42 100644 --- a/.github/workflows/help-comment-issue.yml +++ b/.github/workflows/help-comment-issue.yml @@ -1,22 +1,9 @@ -# Copyright © 2023 OpenIM. 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. - name: Good frist issue add comment on: issues: types: - labeled + jobs: add-comment: if: github.event.label.name == 'help wanted' || github.event.label.name == 'good first issue' @@ -25,11 +12,11 @@ jobs: issues: write steps: - name: Add comment - uses: peter-evans/create-or-update-comment@v3 + uses: peter-evans/create-or-update-comment@v4 with: issue-number: ${{ github.event.issue.number }} - token: ${{ secrets.BOT_GITHUB_TOKEN }} + token: ${{ secrets.BOT_TOKEN }} body: | This issue is available for anyone to work on. **Make sure to reference this issue in your pull request.** :sparkles: Thank you for your contribution! :sparkles: - [Join slack 🤖](https://join.slack.com/t/openimsdk/shared_invite/zt-1tmoj26uf-_FDy3dowVHBiGvLk9e5Xkg) to connect and communicate with our developers. + [Join slack 🤖](https://join.slack.com/t/openimsdk/shared_invite/zt-22720d66b-o_FvKxMTGXtcnnnHiMqe9Q) to connect and communicate with our developers. If you wish to accept this assignment, please leave a comment in the comments section: `/accept`.🎯 \ No newline at end of file diff --git a/.github/workflows/issue-translator.yml b/.github/workflows/issue-translator.yml new file mode 100644 index 000000000..6a8528ae6 --- /dev/null +++ b/.github/workflows/issue-translator.yml @@ -0,0 +1,19 @@ +name: 'issue-translator' +on: + issue_comment: + types: [created] + issues: + types: [opened] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: usthe/issues-translate-action@v2.7 + with: + BOT_GITHUB_TOKEN: ${{ secrets.BOT_TOKEN }} + IS_MODIFY_TITLE: true + # not require, default false, . Decide whether to modify the issue title + # if true, the robot account @Issues-translate-bot must have modification permissions, invite @Issues-translate-bot to your project or use your custom bot. + CUSTOM_BOT_NOTE: Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿 + # not require. Customize the translation robot prefix message. \ No newline at end of file diff --git a/.github/workflows/language-check.yml b/.github/workflows/language-check.yml deleted file mode 100644 index 904323cd9..000000000 --- a/.github/workflows/language-check.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: Language Check Workflow Test - -on: [pull_request] - -jobs: - comment-language-detector: - runs-on: ubuntu-latest - steps: - - name: Checkout Repository - uses: actions/checkout@v2 - - - name: Code Language Detector - uses: kubecub/comment-lang-detector@v1.0.0 diff --git a/.github/workflows/project-progress.yml b/.github/workflows/project-progress.yml deleted file mode 100644 index e6a7156e1..000000000 --- a/.github/workflows/project-progress.yml +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -# GitHub recommends pinning actions to a commit SHA. -# To get a newer version, you will need to update the SHA. -# You can also reference a tag or branch, but the action may change without warning. - -name: Move assigned card -on: - issues: - types: - - assigned - pull_request: - types: - - assigned - -jobs: - move-assigned-card: - runs-on: ubuntu-latest - steps: - - uses: alex-page/github-project-automation-plus@v0.8.3 - with: - project: OpenIM-V3.1 - column: In Progress - repo-token: ${{ secrets.BOT_GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml deleted file mode 100644 index cb5c39fc9..000000000 --- a/.github/workflows/pull-request.yml +++ /dev/null @@ -1,115 +0,0 @@ -name: Github Pull Request -on: - workflow_dispatch: - schedule: - - cron: '0 2 * * *' - -permissions: - contents: write - pull-requests: write - -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - uses: actions/setup-node@v4 - - name: Setup Go - uses: actions/setup-go@v5 - - name: Run go modules tidy - run: | - sudo apt-get install jq - sudo make tidy - sudo make tools.verify.go-gitlint - echo "Run go modules tidy successfully" - continue-on-error: true - - - name: Run go format and lint - run: | - sudo make format - echo "Run go format successfully" - continue-on-error: true - - - name: Run go lint - run: | - sudo make lint - echo "Run go lint successfully" - continue-on-error: true - - - name: Generate all necessary files, such as error code files - run: | - make generate - echo "Generate all necessary files successfully" - continue-on-error: true - - - name: make init - run: | - export OPENIM_IP=127.0.0.1 - export LOG_STORAGE_LOCATION="../logs/" - ./scripts/init-config.sh --examples --force - echo "Generate all necessary files successfully" - continue-on-error: true - - - name: Generate Vertions - run: | - latest_tag=$(git describe --tags `git rev-list --tags --max-count=1` | grep -oE '[0-9]+\.[0-9]+\.[0-9]+') - echo $latest_tag > pkg/common/config/version - continue-on-error: true - - - name: Gen CHANGELOG file - run: | - current_tag=$(git describe --tags --abbrev=0) - version=$(echo "$current_tag" | sed -E 's/^v?([0-9]+)\.([0-9]+)\..*$/\1.\2/') - echo "OpenIM Version: $version" - make tools.install.git-chglog - cd CHANGELOG - git-chglog --tag-filter-pattern "v${version}.*" -o CHANGELOG-${version}.md - cd .. - continue-on-error: true - - - name: Run unit test and get test coverage - run: | - make cover - echo "Run unit test and get test coverage successfully" - continue-on-error: true - - - name: OpenIM verify copyright - run: | - sudo make add-copyright - echo "OpenIM verify successfully" - continue-on-error: true - - - name: Create Pull Request - uses: peter-evans/create-pull-request@v6 - with: - token: ${{ secrets.BOT_GITHUB_TOKEN }} - commit-message: "cicd: bump League Patch" - author: kubbot <3293172751ysy@gmail.com> - committer: kubbot <3293172751ysy@gmail.com> - # signoff: false - # draft: false - branch: "asf-auto-updates" - assignees: cubxxw - reviewers: cubxxw - title: "[Auto PR 🤖] Bump League Patch auto PR" - body: | - I am a PR generated by robot automation. - - Review criteria: - - - [ ] Disenchanter can connect and issue actions - - Github Actions Status: - - [![Github Pull Request](https://github.com/openimsdk/chat/actions/workflows/pull-request.yml/badge.svg)](https://github.com/openimsdk/open-im-server/actions/workflows/pull-request.yml) - - This is an automated PR. - [workflow](https://github.com/openimsdk/chat/blob/main/.github/workflows/pull-request.yml). - labels: | - kind/documentation - enhancement - report diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d133b9d07..a46b1c8bd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,17 +1,3 @@ -# Copyright © 2023 OpenIM open source community. 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. - name: OpenIM chat release on: diff --git a/.github/workflows/reopen-issue.yml b/.github/workflows/reopen-issue.yml new file mode 100644 index 000000000..d12e2c30e --- /dev/null +++ b/.github/workflows/reopen-issue.yml @@ -0,0 +1,78 @@ +name: Reopen and Update Stale Issues + +on: + workflow_dispatch: + +jobs: + reopen_stale_issues: + runs-on: ubuntu-latest + permissions: + issues: write + contents: read + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Fetch Closed Issues with lifecycle/stale Label + id: fetch_issues + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const issues = await github.paginate(github.rest.issues.listForRepo, { + owner: context.repo.owner, + repo: context.repo.repo, + state: 'closed', + labels: 'lifecycle/stale', + per_page: 100 + }); + const issueNumbers = issues + .filter(issue => !issue.pull_request) + .map(issue => issue.number); + console.log(`Fetched issues: ${issueNumbers}`); + return issueNumbers; + + - name: Set issue numbers + id: set_issue_numbers + run: | + echo "ISSUE_NUMBERS=${{ steps.fetch_issues.outputs.result }}" >> $GITHUB_ENV + echo "Issue numbers: ${{ steps.fetch_issues.outputs.result }}" + + - name: Reopen Issues + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const issueNumbers = JSON.parse(process.env.ISSUE_NUMBERS); + console.log(`Reopening issues: ${issueNumbers}`); + + for (const issue_number of issueNumbers) { + // Reopen the issue + await github.rest.issues.update({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue_number, + state: 'open' + }); + console.log(`Reopened issue #${issue_number}`); + } + + - name: Remove lifecycle/stale Label + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const issueNumbers = JSON.parse(process.env.ISSUE_NUMBERS); + console.log(`Removing 'lifecycle/stale' label from issues: ${issueNumbers}`); + + for (const issue_number of issueNumbers) { + // Remove the lifecycle/stale label + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue_number, + name: 'lifecycle/stale' + }); + console.log(`Removed label 'lifecycle/stale' from issue #${issue_number}`); + } diff --git a/.github/workflows/update-version-file-on-release.yml b/.github/workflows/update-version-file-on-release.yml new file mode 100644 index 000000000..f582edf48 --- /dev/null +++ b/.github/workflows/update-version-file-on-release.yml @@ -0,0 +1,84 @@ +name: Update Version File on Release + +on: + release: + types: [created] + +jobs: + update-version: + runs-on: ubuntu-latest + env: + TAG_VERSION: ${{ github.event.release.tag_name }} + steps: + # Step 1: Checkout the original repository's code + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + # Step 2: Set up Git with official account + - name: Set up Git + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + # Step 3: Check and delete existing tag + - name: Check and delete existing tag + run: | + if git rev-parse ${{ env.TAG_VERSION }} >/dev/null 2>&1; then + git tag -d ${{ env.TAG_VERSION }} + git push --delete origin ${{ env.TAG_VERSION }} + fi + + # Step 4: Update version file + - name: Update version file + run: | + echo "${{ env.TAG_VERSION }}" > version/version + + # Step 5: Commit and push changes + - name: Commit and push changes + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git add version/version + git commit -m "Update version to ${{ env.TAG_VERSION }}" + git push origin HEAD:${{ github.ref }} + + # Step 6: Create and push tag + - name: Create and push tag + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git tag ${{ env.TAG_VERSION }} + git push origin ${{ env.TAG_VERSION }} + + # Step 8: Find and Publish Draft Release + - name: Find and Publish Draft Release + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + // Get the list of releases + const releases = await github.rest.repos.listReleases({ + owner: context.repo.owner, + repo: context.repo.repo + }); + + // Find the draft release where the title and tag_name are the same + const draftRelease = releases.data.find(release => + release.draft && release.name === release.tag_name + ); + + if (draftRelease) { + // Publish the draft release using the release_id + await github.rest.repos.updateRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: draftRelease.id, // Use release_id + draft: false + }); + + core.info(`Draft Release ${draftRelease.tag_name} published successfully.`); + } else { + core.info("No matching draft release found."); + } \ No newline at end of file diff --git a/HOW_TO_SETUP_LIVEKIT_SERVER.md b/HOW_TO_SETUP_LIVEKIT_SERVER.md index c8c6dd23e..a5762a13b 100644 --- a/HOW_TO_SETUP_LIVEKIT_SERVER.md +++ b/HOW_TO_SETUP_LIVEKIT_SERVER.md @@ -9,6 +9,7 @@ OpenIM Chat uses the LiveKit server as the media server to support video calls a ## Quick Start To self-host LiveKit, start the server with the following Docker command: +> replace `your-server-ip` with your server IP address ```bash docker run -d \ @@ -18,7 +19,8 @@ docker run -d \ -v $PWD/livekit/livekit.yaml:/livekit.yaml \ livekit/livekit-server \ --config /livekit.yaml \ - --bind 0.0.0.0 + --bind 0.0.0.0 \ + --node-ip=your-server-ip ``` ## Viewing Logs diff --git a/config/log.yml b/config/log.yml index 44ff3ee71..8620af611 100644 --- a/config/log.yml +++ b/config/log.yml @@ -10,3 +10,5 @@ remainLogLevel: 6 isStdout: false # Whether to log in JSON format, default is acceptable isJson: false +# output simplify log when KeyAndValues's value len is bigger than 50 in rpc method log +isSimplify: true \ No newline at end of file diff --git a/go.mod b/go.mod index 723dd02e8..2b84c4af7 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,6 @@ require ( github.com/golang/protobuf v1.5.4 // indirect github.com/google/uuid v1.6.0 github.com/jinzhu/copier v0.4.0 // indirect - github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect google.golang.org/grpc v1.62.1 google.golang.org/protobuf v1.33.0 @@ -26,8 +25,8 @@ require ( github.com/livekit/protocol v1.10.1 github.com/mitchellh/mapstructure v1.5.0 github.com/openimsdk/gomake v0.0.14-alpha.5 - github.com/openimsdk/protocol v0.0.63 - github.com/openimsdk/tools v0.0.49-alpha.24 + github.com/openimsdk/protocol v0.0.72 + github.com/openimsdk/tools v0.0.50-alpha.15 github.com/redis/go-redis/v9 v9.5.1 github.com/spf13/cobra v1.8.0 github.com/spf13/viper v1.18.2 diff --git a/go.sum b/go.sum index 6587e0cdc..a4f7c8ac8 100644 --- a/go.sum +++ b/go.sum @@ -187,10 +187,10 @@ github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OS github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/openimsdk/gomake v0.0.14-alpha.5 h1:VY9c5x515lTfmdhhPjMvR3BBRrRquAUCFsz7t7vbv7Y= github.com/openimsdk/gomake v0.0.14-alpha.5/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI= -github.com/openimsdk/protocol v0.0.63 h1:9DnweZe9nEYDFa4fGTbC9Cqi0gLUdtBhRo1NRP2X3WQ= -github.com/openimsdk/protocol v0.0.63/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8= -github.com/openimsdk/tools v0.0.49-alpha.24 h1:lJsqnjTPujnr91LRQ6QmcTliMIa4fMOBSTri6rFz2ek= -github.com/openimsdk/tools v0.0.49-alpha.24/go.mod h1:g7mkHXYUPi0/8aAX8VPMHpnb3hqdV69Jph+bXOGvvNM= +github.com/openimsdk/protocol v0.0.72 h1:K+vslwaR7lDXyBzb07UuEQITaqsgighz7NyXVIWsu6A= +github.com/openimsdk/protocol v0.0.72/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8= +github.com/openimsdk/tools v0.0.50-alpha.15 h1:HV9aKZ4vvCZCGG4wFDsgUONkkdJeCcrFNn3BT52nUVQ= +github.com/openimsdk/tools v0.0.50-alpha.15/go.mod h1:h1cYmfyaVtgFbKmb1Cfsl8XwUOMTt8ubVUQrdGtsUh4= github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pion/datachannel v1.5.5 h1:10ef4kwdjije+M9d7Xm9im2Y3O6A6ccQb0zcqZcJew8= diff --git a/internal/api/admin/admin.go b/internal/api/admin/admin.go index e0586939c..7e0a44893 100644 --- a/internal/api/admin/admin.go +++ b/internal/api/admin/admin.go @@ -18,6 +18,11 @@ import ( "context" "crypto/md5" "encoding/hex" + "net/http" + "strconv" + "strings" + "time" + "github.com/gin-gonic/gin" "github.com/openimsdk/chat/internal/api/util" "github.com/openimsdk/chat/pkg/common/apistruct" @@ -37,10 +42,6 @@ import ( "github.com/openimsdk/tools/log" "github.com/openimsdk/tools/utils/datautil" "github.com/openimsdk/tools/utils/encrypt" - "net/http" - "strconv" - "strings" - "time" ) func New(chatClient chat.ChatClient, adminClient admin.AdminClient, imApiCaller imapi.CallerInterface, api *util.Api) *Api { @@ -71,7 +72,7 @@ func (o *Api) AdminLogin(c *gin.Context) { return } imAdminUserID := o.GetDefaultIMAdminUserID() - imToken, err := o.imApiCaller.UserToken(c, imAdminUserID, constant.AdminPlatformID) + imToken, err := o.imApiCaller.GetAdminToken(c, imAdminUserID) if err != nil { apiresp.GinError(c, err) return @@ -87,7 +88,30 @@ func (o *Api) AdminLogin(c *gin.Context) { } func (o *Api) ResetUserPassword(c *gin.Context) { - a2r.Call(chat.ChatClient.ChangePassword, o.chatClient, c) + req, err := a2r.ParseRequest[chat.ChangePasswordReq](c) + if err != nil { + apiresp.GinError(c, err) + return + } + resp, err := o.chatClient.ChangePassword(c, req) + if err != nil { + apiresp.GinError(c, err) + return + } + + imToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) + if err != nil { + apiresp.GinError(c, err) + return + } + + err = o.imApiCaller.ForceOffLine(mctx.WithApiToken(c, imToken), req.UserID) + if err != nil { + apiresp.GinError(c, err) + return + } + + apiresp.GinSuccess(c, resp) } func (o *Api) AdminUpdateInfo(c *gin.Context) { @@ -103,7 +127,7 @@ func (o *Api) AdminUpdateInfo(c *gin.Context) { } imAdminUserID := o.GetDefaultIMAdminUserID() - imToken, err := o.imApiCaller.UserToken(c, imAdminUserID, constant.AdminPlatformID) + imToken, err := o.imApiCaller.GetAdminToken(c, imAdminUserID) if err != nil { log.ZError(c, "AdminUpdateInfo ImAdminTokenWithDefaultAdmin", err, "imAdminUserID", imAdminUserID) return @@ -183,7 +207,7 @@ func (o *Api) AddDefaultGroup(c *gin.Context) { apiresp.GinError(c, err) return } - imToken, err := o.imApiCaller.UserToken(c, o.GetDefaultIMAdminUserID(), constant.AdminPlatformID) + imToken, err := o.imApiCaller.GetAdminToken(c, o.GetDefaultIMAdminUserID()) if err != nil { apiresp.GinError(c, err) return @@ -231,7 +255,7 @@ func (o *Api) SearchDefaultGroup(c *gin.Context) { Groups: make([]*sdkws.GroupInfo, 0, len(searchResp.GroupIDs)), } if len(searchResp.GroupIDs) > 0 { - imToken, err := o.imApiCaller.UserToken(c, o.GetDefaultIMAdminUserID(), constant.AdminPlatformID) + imToken, err := o.imApiCaller.GetAdminToken(c, o.GetDefaultIMAdminUserID()) if err != nil { apiresp.GinError(c, err) return @@ -313,7 +337,7 @@ func (o *Api) BlockUser(c *gin.Context) { apiresp.GinError(c, err) return } - imToken, err := o.imApiCaller.UserToken(c, o.GetDefaultIMAdminUserID(), constant.AdminPlatformID) + imToken, err := o.imApiCaller.GetAdminToken(c, o.GetDefaultIMAdminUserID()) if err != nil { apiresp.GinError(c, err) return @@ -372,7 +396,7 @@ func (o *Api) NewUserCount(c *gin.Context) { apiresp.GinError(c, err) return } - imToken, err := o.imApiCaller.UserToken(c, o.GetDefaultIMAdminUserID(), constant.AdminPlatformID) + imToken, err := o.imApiCaller.GetAdminToken(c, o.GetDefaultIMAdminUserID()) if err != nil { apiresp.GinError(c, err) return diff --git a/internal/api/chat/chat.go b/internal/api/chat/chat.go index 6ab2e4bbc..eca5e3bbe 100644 --- a/internal/api/chat/chat.go +++ b/internal/api/chat/chat.go @@ -132,7 +132,7 @@ func (o *Api) RegisterUser(c *gin.Context) { FaceURL: req.User.FaceURL, CreateTime: time.Now().UnixMilli(), } - err = o.imApiCaller.RegisterUser(c, []*sdkws.UserInfo{userInfo}) + err = o.imApiCaller.RegisterUser(apiCtx, []*sdkws.UserInfo{userInfo}) if err != nil { apiresp.GinError(c, err) return @@ -146,7 +146,7 @@ func (o *Api) RegisterUser(c *gin.Context) { } var resp apistruct.UserRegisterResp if req.AutoLogin { - resp.ImToken, err = o.imApiCaller.UserToken(c, respRegisterUser.UserID, req.Platform) + resp.ImToken, err = o.imApiCaller.GetUserToken(apiCtx, respRegisterUser.UserID, req.Platform) if err != nil { apiresp.GinError(c, err) return @@ -174,7 +174,14 @@ func (o *Api) Login(c *gin.Context) { apiresp.GinError(c, err) return } - imToken, err := o.imApiCaller.UserToken(c, resp.UserID, req.Platform) + adminToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) + if err != nil { + apiresp.GinError(c, err) + return + } + apiCtx := mctx.WithApiToken(c, adminToken) + + imToken, err := o.imApiCaller.GetUserToken(apiCtx, resp.UserID, req.Platform) if err != nil { apiresp.GinError(c, err) return @@ -237,7 +244,7 @@ func (o *Api) UpdateUserInfo(c *gin.Context) { if opUserType == constant.NormalUser { imToken, err = o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) } else if opUserType == constant.AdminUser { - imToken, err = o.imApiCaller.UserToken(c, o.GetDefaultIMAdminUserID(), constantpb.AdminPlatformID) + imToken, err = o.imApiCaller.GetAdminToken(c, o.GetDefaultIMAdminUserID()) } else { apiresp.GinError(c, errs.ErrArgs.WrapMsg("opUserType unknown")) return diff --git a/internal/rpc/chat/login.go b/internal/rpc/chat/login.go index f1f2474b8..59990302d 100644 --- a/internal/rpc/chat/login.go +++ b/internal/rpc/chat/login.go @@ -240,8 +240,6 @@ func (o *chatSvr) genVerifyCode() string { } func (o *chatSvr) RegisterUser(ctx context.Context, req *chat.RegisterUserReq) (*chat.RegisterUserResp, error) { - resp := &chat.RegisterUserResp{} - isAdmin, err := o.Admin.CheckNilOrAdmin(ctx) ctx = o.WithAdminUser(ctx) if err != nil { @@ -389,6 +387,7 @@ func (o *chatSvr) RegisterUser(ctx context.Context, req *chat.RegisterUserReq) ( log.ZError(ctx, "UseInvitationCode", err, "userID", req.User.UserID, "invitationCode", req.InvitationCode) } } + var resp chat.RegisterUserResp if req.AutoLogin { chatToken, err := o.Admin.CreateToken(ctx, req.User.UserID, constant.NormalUser) if err == nil { @@ -398,7 +397,7 @@ func (o *chatSvr) RegisterUser(ctx context.Context, req *chat.RegisterUserReq) ( } } resp.UserID = req.User.UserID - return resp, nil + return &resp, nil } func (o *chatSvr) Login(ctx context.Context, req *chat.LoginReq) (*chat.LoginResp, error) { diff --git a/internal/rpc/chat/update.go b/internal/rpc/chat/update.go index 169694fff..4579f1c3e 100644 --- a/internal/rpc/chat/update.go +++ b/internal/rpc/chat/update.go @@ -63,8 +63,8 @@ func ToDBAttributeUpdate(req *chat.UpdateUserInfoReq) (map[string]any, error) { if req.GlobalRecvMsgOpt != nil { update["global_recv_msg_opt"] = req.GlobalRecvMsgOpt.Value } - if len(update) == 0 { - return nil, errs.ErrArgs.WrapMsg("no update info") - } + //if len(update) == 0 { + // return nil, errs.ErrArgs.WrapMsg("no update info") + //} return update, nil } diff --git a/internal/rpc/chat/user.go b/internal/rpc/chat/user.go index ff53c9177..ce789613a 100644 --- a/internal/rpc/chat/user.go +++ b/internal/rpc/chat/user.go @@ -32,8 +32,95 @@ import ( "github.com/openimsdk/tools/errs" ) +func (o *chatSvr) checkUpdateInfo(ctx context.Context, req *chat.UpdateUserInfoReq) error { + attribute, err := o.Database.TakeAttributeByUserID(ctx, req.UserID) + if err != nil { + return err + } + checkEmail := func() error { + if req.Email == nil { + return nil + } + if req.Email.Value == attribute.Email { + req.Email = nil + return nil + } + if req.Email.Value == "" { + if !(attribute.Account != "" || (attribute.AreaCode != "" && attribute.PhoneNumber != "")) { + return errs.ErrArgs.WrapMsg("a login method must exist") + } + return nil + } else { + if _, err := o.Database.GetAttributeByEmail(ctx, req.Email.Value); err == nil { + return errs.ErrDuplicateKey.WrapMsg("email already exists") + } else if !dbutil.IsDBNotFound(err) { + return err + } + } + return nil + } + checkPhone := func() error { + if req.AreaCode == nil { + return nil + } + if req.AreaCode.Value == attribute.AreaCode && req.PhoneNumber.Value == attribute.PhoneNumber { + req.AreaCode = nil + req.PhoneNumber = nil + return nil + } + if req.AreaCode.Value == "" || req.PhoneNumber.Value == "" { + if attribute.Email == "" || attribute.Account == "" { + return errs.ErrArgs.WrapMsg("a login method must exist") + } + } else { + if _, err := o.Database.GetAttributeByPhone(ctx, req.AreaCode.Value, req.PhoneNumber.Value); err == nil { + return errs.ErrDuplicateKey.WrapMsg("phone number already exists") + } else if !dbutil.IsDBNotFound(err) { + return err + } + } + return nil + } + checkAccount := func() error { + if req.Account == nil { + return nil + } + if req.Account.Value == attribute.Account { + req.Account = nil + return nil + } + if req.Account.Value == "" { + if !(attribute.Email == "" && (attribute.AreaCode == "" || attribute.PhoneNumber == "")) { + return errs.ErrArgs.WrapMsg("a login method must exist") + } + } else { + if _, err := o.Database.GetAttributeByAccount(ctx, req.Account.Value); err == nil { + return errs.ErrDuplicateKey.WrapMsg("account already exists") + } else if !dbutil.IsDBNotFound(err) { + return err + } + } + return nil + } + for _, fn := range []func() error{checkEmail, checkPhone, checkAccount} { + if err := fn(); err != nil { + return err + } + } + return nil +} + func (o *chatSvr) UpdateUserInfo(ctx context.Context, req *chat.UpdateUserInfoReq) (*chat.UpdateUserInfoResp, error) { - resp := &chat.UpdateUserInfoResp{} + if req.AreaCode != nil || req.PhoneNumber != nil { + if !(req.AreaCode != nil && req.PhoneNumber != nil) { + return nil, errs.ErrArgs.WrapMsg("areaCode and phoneNumber must be set together") + } + if req.AreaCode.Value == "" || req.PhoneNumber.Value == "" { + if req.AreaCode.Value != req.PhoneNumber.Value { + return nil, errs.ErrArgs.WrapMsg("areaCode and phoneNumber must be set together") + } + } + } opUserID, userType, err := mctx.Check(ctx) if err != nil { return nil, err @@ -65,44 +152,19 @@ func (o *chatSvr) UpdateUserInfo(ctx context.Context, req *chat.UpdateUserInfoRe default: return nil, errs.ErrNoPermission.WrapMsg("user type error") } - update, err := ToDBAttributeUpdate(req) - if err != nil { + if err := o.checkUpdateInfo(ctx, req); err != nil { return nil, err } - attribute, err := o.Database.TakeAttributeByUserID(ctx, req.UserID) + update, err := ToDBAttributeUpdate(req) if err != nil { return nil, err } - if req.Account != nil && req.Account.Value != attribute.Account { - _, err := o.Database.TakeAttributeByAccount(ctx, req.Account.Value) - if err == nil { - return nil, eerrs.ErrAccountAlreadyRegister.Wrap() - } else if !dbutil.IsDBNotFound(err) { + if len(update) > 0 { + if err := o.Database.UpdateUseInfo(ctx, req.UserID, update); err != nil { return nil, err } } - if req.AreaCode != nil || req.PhoneNumber != nil { - areaCode := attribute.AreaCode - phoneNumber := attribute.PhoneNumber - if req.AreaCode != nil { - areaCode = req.AreaCode.Value - } - if req.PhoneNumber != nil { - phoneNumber = req.PhoneNumber.Value - } - if attribute.AreaCode != areaCode || attribute.PhoneNumber != phoneNumber { - _, err := o.Database.TakeAttributeByPhone(ctx, areaCode, phoneNumber) - if err == nil { - return nil, eerrs.ErrAccountAlreadyRegister.Wrap() - } else if !dbutil.IsDBNotFound(err) { - return nil, err - } - } - } - if err := o.Database.UpdateUseInfo(ctx, req.UserID, update); err != nil { - return nil, err - } - return resp, nil + return &chat.UpdateUserInfoResp{}, nil } func (o *chatSvr) FindUserPublicInfo(ctx context.Context, req *chat.FindUserPublicInfoReq) (*chat.FindUserPublicInfoResp, error) { diff --git a/livekit/livekit.yaml b/livekit/livekit.yaml index e199bbf00..b6243f2cf 100644 --- a/livekit/livekit.yaml +++ b/livekit/livekit.yaml @@ -3,7 +3,7 @@ rtc: tcp_port: 7881 port_range_start: 50000 port_range_end: 60000 - use_external_ip: true + use_external_ip: false enable_loopback_candidate: false keys: APIGPW3gnFTzqHH: 23ztfSqsfQ8hKkHzHTl3Z4bvaxro0snjk5jwbp5p6Q3 \ No newline at end of file diff --git a/pkg/common/cmd/root.go b/pkg/common/cmd/root.go index 7c4a3075a..762cbacd8 100644 --- a/pkg/common/cmd/root.go +++ b/pkg/common/cmd/root.go @@ -16,9 +16,11 @@ package cmd import ( "fmt" - "github.com/openimsdk/chat/pkg/common/config" "path/filepath" + "github.com/openimsdk/chat/pkg/common/config" + "github.com/openimsdk/chat/version/version" + "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/log" "github.com/spf13/cobra" @@ -117,16 +119,18 @@ func (r *RootCmd) applyOptions(opts ...func(*CmdOpts)) *CmdOpts { } func (r *RootCmd) initializeLogger(cmdOpts *CmdOpts) error { - err := log.InitFromConfig( + err := log.InitLoggerFromConfig( cmdOpts.loggerPrefixName, r.processName, + "", "", r.log.RemainLogLevel, r.log.IsStdout, r.log.IsJson, r.log.StorageLocation, r.log.RemainRotationCount, r.log.RotationTime, - config.Version, + version.Version, + r.log.IsSimplify, ) if err != nil { return errs.Wrap(err) diff --git a/pkg/common/config/config.go b/pkg/common/config/config.go index 6f926660a..76acd6c65 100644 --- a/pkg/common/config/config.go +++ b/pkg/common/config/config.go @@ -2,6 +2,7 @@ package config import ( _ "embed" + "github.com/openimsdk/tools/db/mongoutil" "github.com/openimsdk/tools/db/redisutil" ) @@ -165,5 +166,6 @@ type Log struct { RemainLogLevel int `mapstructure:"remainLogLevel"` IsStdout bool `mapstructure:"isStdout"` IsJson bool `mapstructure:"isJson"` + IsSimplify bool `mapstructure:"isSimplify"` WithStack bool `mapstructure:"withStack"` } diff --git a/pkg/common/imapi/api.go b/pkg/common/imapi/api.go index 6d5aff2fd..60891be0f 100644 --- a/pkg/common/imapi/api.go +++ b/pkg/common/imapi/api.go @@ -16,21 +16,22 @@ package imapi import ( "github.com/openimsdk/protocol/auth" - "github.com/openimsdk/protocol/friend" "github.com/openimsdk/protocol/group" + "github.com/openimsdk/protocol/relation" "github.com/openimsdk/protocol/user" ) // im caller. var ( - importFriend = NewApiCaller[friend.ImportFriendReq, friend.ImportFriendResp]("/friend/import_friend") - userToken = NewApiCaller[auth.UserTokenReq, auth.UserTokenResp]("/auth/user_token") + importFriend = NewApiCaller[relation.ImportFriendReq, relation.ImportFriendResp]("/friend/import_friend") + getAdminToken = NewApiCaller[auth.GetAdminTokenReq, auth.GetAdminTokenResp]("/auth/get_admin_token") + getuserToken = NewApiCaller[auth.GetUserTokenReq, auth.GetUserTokenResp]("/auth/get_user_token") inviteToGroup = NewApiCaller[group.InviteUserToGroupReq, group.InviteUserToGroupResp]("/group/invite_user_to_group") updateUserInfo = NewApiCaller[user.UpdateUserInfoReq, user.UpdateUserInfoResp]("/user/update_user_info") registerUser = NewApiCaller[user.UserRegisterReq, user.UserRegisterResp]("/user/user_register") forceOffLine = NewApiCaller[auth.ForceLogoutReq, auth.ForceLogoutResp]("/auth/force_logout") getGroupsInfo = NewApiCaller[group.GetGroupsInfoReq, group.GetGroupsInfoResp]("/group/get_groups_info") registerUserCount = NewApiCaller[user.UserRegisterCountReq, user.UserRegisterCountResp]("/statistics/user/register") - friendUserIDs = NewApiCaller[friend.GetFriendIDsReq, friend.GetFriendIDsResp]("/friend/get_friend_id") + friendUserIDs = NewApiCaller[relation.GetFriendIDsReq, relation.GetFriendIDsResp]("/friend/get_friend_id") accountCheck = NewApiCaller[user.AccountCheckReq, user.AccountCheckResp]("/user/account_check") ) diff --git a/pkg/common/imapi/caller.go b/pkg/common/imapi/caller.go index c6ca3f1e6..0a3923cb2 100644 --- a/pkg/common/imapi/caller.go +++ b/pkg/common/imapi/caller.go @@ -23,9 +23,10 @@ import ( "github.com/openimsdk/tools/log" "github.com/openimsdk/protocol/auth" + "github.com/openimsdk/protocol/constant" constantpb "github.com/openimsdk/protocol/constant" - "github.com/openimsdk/protocol/friend" "github.com/openimsdk/protocol/group" + "github.com/openimsdk/protocol/relation" "github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/protocol/user" ) @@ -33,7 +34,8 @@ import ( type CallerInterface interface { ImAdminTokenWithDefaultAdmin(ctx context.Context) (string, error) ImportFriend(ctx context.Context, ownerUserID string, friendUserID []string) error - UserToken(ctx context.Context, userID string, platform int32) (string, error) + GetUserToken(ctx context.Context, userID string, platform int32) (string, error) + GetAdminToken(ctx context.Context, userID string) (string, error) InviteToGroup(ctx context.Context, userID string, groupIDs []string) error UpdateUserInfo(ctx context.Context, userID string, nickName string, faceURL string) error ForceOffLine(ctx context.Context, userID string) error @@ -65,7 +67,7 @@ func (c *Caller) ImportFriend(ctx context.Context, ownerUserID string, friendUse if len(friendUserIDs) == 0 { return nil } - _, err := importFriend.Call(ctx, c.imApi, &friend.ImportFriendReq{ + _, err := importFriend.Call(ctx, c.imApi, &relation.ImportFriendReq{ OwnerUserID: ownerUserID, FriendUserIDs: friendUserIDs, }) @@ -77,7 +79,7 @@ func (c *Caller) ImAdminTokenWithDefaultAdmin(ctx context.Context) (string, erro defer c.lock.Unlock() if c.token == "" || c.timeout.Before(time.Now()) { userID := c.defaultIMUserID - token, err := c.UserToken(ctx, userID, constantpb.AdminPlatformID) + token, err := c.GetAdminToken(ctx, userID) if err != nil { log.ZError(ctx, "get im admin token", err, "userID", userID) return "", err @@ -89,9 +91,19 @@ func (c *Caller) ImAdminTokenWithDefaultAdmin(ctx context.Context) (string, erro return c.token, nil } -func (c *Caller) UserToken(ctx context.Context, userID string, platformID int32) (string, error) { - resp, err := userToken.Call(ctx, c.imApi, &auth.UserTokenReq{ - Secret: c.imSecret, +func (c *Caller) GetAdminToken(ctx context.Context, userID string) (string, error) { + resp, err := getAdminToken.Call(ctx, c.imApi, &auth.GetAdminTokenReq{ + Secret: c.imSecret, + UserID: userID, + }) + if err != nil { + return "", err + } + return resp.Token, nil +} + +func (c *Caller) GetUserToken(ctx context.Context, userID string, platformID int32) (string, error) { + resp, err := getuserToken.Call(ctx, c.imApi, &auth.GetUserTokenReq{ PlatformID: platformID, UserID: userID, }) @@ -123,8 +135,7 @@ func (c *Caller) UpdateUserInfo(ctx context.Context, userID string, nickName str func (c *Caller) RegisterUser(ctx context.Context, users []*sdkws.UserInfo) error { _, err := registerUser.Call(ctx, c.imApi, &user.UserRegisterReq{ - Secret: c.imSecret, - Users: users, + Users: users, }) return err } @@ -161,7 +172,7 @@ func (c *Caller) UserRegisterCount(ctx context.Context, start int64, end int64) } func (c *Caller) FriendUserIDs(ctx context.Context, userID string) ([]string, error) { - resp, err := friendUserIDs.Call(ctx, c.imApi, &friend.GetFriendIDsReq{UserID: userID}) + resp, err := friendUserIDs.Call(ctx, c.imApi, &relation.GetFriendIDsReq{UserID: userID}) if err != nil { return nil, err } @@ -174,7 +185,7 @@ func (c *Caller) AccountCheckSingle(ctx context.Context, userID string) (bool, e if err != nil { return false, err } - if resp.Results[0].AccountStatus == "registered" { + if resp.Results[0].AccountStatus == constant.Registered { return false, eerrs.ErrAccountAlreadyRegister.Wrap() } return true, nil diff --git a/pkg/protocol/sdkws/sdkws.proto b/pkg/protocol/sdkws/sdkws.proto index 8032ed836..57301c5be 100644 --- a/pkg/protocol/sdkws/sdkws.proto +++ b/pkg/protocol/sdkws/sdkws.proto @@ -14,12 +14,14 @@ syntax = "proto3"; package openim.sdkws; + import "wrapperspb/wrapperspb.proto"; + option go_package = "github.com/openimsdk/protocol/sdkws"; ////////////////////////////////base/////////////////////////////// -message GroupInfo{ +message GroupInfo { string groupID = 1; string groupName = 2; string notification = 3; @@ -39,7 +41,7 @@ message GroupInfo{ string notificationUserID = 17; } -message GroupInfoForSet{ +message GroupInfoForSet { string groupID = 1; string groupName = 2; string notification = 3; @@ -51,10 +53,9 @@ message GroupInfoForSet{ openim.protobuf.Int32Value applyMemberFriend = 9; } - message GroupMemberFullInfo { - string groupID = 1 ; - string userID = 2 ; + string groupID = 1; + string userID = 2; int32 roleLevel = 3; int64 joinTime = 4; string nickname = 5; @@ -67,14 +68,14 @@ message GroupMemberFullInfo { string inviterUserID = 12; } -message PublicUserInfo{ +message PublicUserInfo { string userID = 1; string nickname = 2; string faceURL = 3; string ex = 4; } -message UserInfo{ +message UserInfo { string userID = 1; string nickname = 2; string faceURL = 3; @@ -84,7 +85,7 @@ message UserInfo{ int32 globalRecvMsgOpt = 7; } -message UserInfoWithEx{ +message UserInfoWithEx { string userID = 1; openim.protobuf.StringValue nickname = 2; openim.protobuf.StringValue faceURL = 3; @@ -92,7 +93,7 @@ message UserInfoWithEx{ openim.protobuf.Int32Value globalRecvMsgOpt = 7; } -message FriendInfo{ +message FriendInfo { string ownerUserID = 1; string remark = 2; int64 createTime = 3; @@ -103,7 +104,7 @@ message FriendInfo{ bool isPinned = 8; } -message BlackInfo{ +message BlackInfo { string ownerUserID = 1; int64 createTime = 2; PublicUserInfo blackUserInfo = 3; @@ -112,12 +113,12 @@ message BlackInfo{ string ex = 6; } -message GroupRequest{ +message GroupRequest { PublicUserInfo userInfo = 1; GroupInfo groupInfo = 2; int32 handleResult = 3; string reqMsg = 4; - string handleMsg = 5; + string handleMsg = 5; int64 reqTime = 6; string handleUserID = 7; int64 handleTime = 8; @@ -126,7 +127,7 @@ message GroupRequest{ string inviterUserID = 11; } -message FriendRequest{ +message FriendRequest { string fromUserID = 1; string fromNickname = 2; string fromFaceURL = 3; @@ -142,14 +143,12 @@ message FriendRequest{ string ex = 13; } - ///////////////////////////////////base end///////////////////////////////////// -enum PullOrder{ +enum PullOrder { PullOrderAsc = 0; PullOrderDesc = 1; - } -message PullMessageBySeqsReq{ +message PullMessageBySeqsReq { string userID = 1; repeated SeqRange seqRanges = 2; PullOrder order = 3; @@ -184,19 +183,19 @@ message GetMaxSeqResp { message UserSendMsgResp { string serverMsgID = 1; string clientMsgID = 2; - int64 sendTime = 3; + int64 sendTime = 3; } message MsgData { - string sendID = 1; - string recvID = 2; + string sendID = 1; + string recvID = 2; string groupID = 3; string clientMsgID = 4; string serverMsgID = 5; int32 senderPlatformID = 6; - string senderNickname = 7; - string senderFaceURL = 8; - int32 sessionType = 9; + string senderNickname = 7; + string senderFaceURL = 8; + int32 sessionType = 9; int32 msgFrom = 10; int32 contentType = 11; bytes content = 12; @@ -211,11 +210,11 @@ message MsgData { string attachedInfo = 22; string ex = 23; } -message PushMessages{ +message PushMessages { map msgs = 1; map notificationMsgs = 2; } -message OfflinePushInfo{ +message OfflinePushInfo { string title = 1; string desc = 2; string ex = 3; @@ -224,7 +223,7 @@ message OfflinePushInfo{ string signalInfo = 6; } -message TipsComm{ +message TipsComm { bytes detail = 1; string defaultTips = 2; string jsonDetail = 3; @@ -232,9 +231,8 @@ message TipsComm{ //////////////////////group///////////////////// - // OnGroupCreated() -message GroupCreatedTips{ +message GroupCreatedTips { GroupInfo group = 1; GroupMemberFullInfo opUser = 2; repeated GroupMemberFullInfo memberList = 3; @@ -243,56 +241,55 @@ message GroupCreatedTips{ } // OnGroupInfoSet() -message GroupInfoSetTips{ +message GroupInfoSetTips { GroupMemberFullInfo opUser = 1; //who do this int64 muteTime = 2; GroupInfo group = 3; } -message GroupInfoSetNameTips{ +message GroupInfoSetNameTips { GroupMemberFullInfo opUser = 1; //who do this GroupInfo group = 2; } -message GroupInfoSetAnnouncementTips{ +message GroupInfoSetAnnouncementTips { GroupMemberFullInfo opUser = 1; //who do this GroupInfo group = 2; } // OnJoinGroupApplication() -message JoinGroupApplicationTips{ +message JoinGroupApplicationTips { GroupInfo group = 1; PublicUserInfo applicant = 2; - string reqMsg = 3; + string reqMsg = 3; } // OnQuitGroup() //Actively leave the group -message MemberQuitTips{ +message MemberQuitTips { GroupInfo group = 1; GroupMemberFullInfo quitUser = 2; int64 operationTime = 3; } - // OnApplicationGroupAccepted() -message GroupApplicationAcceptedTips{ +message GroupApplicationAcceptedTips { GroupInfo group = 1; GroupMemberFullInfo opUser = 2; - string handleMsg = 4; + string handleMsg = 4; int32 receiverAs = 5; // admin(==1) or applicant(==0) } // OnApplicationGroupRejected() -message GroupApplicationRejectedTips{ +message GroupApplicationRejectedTips { GroupInfo group = 1; GroupMemberFullInfo opUser = 2; - string handleMsg = 4; + string handleMsg = 4; int32 receiverAs = 5; // admin(==1) or applicant(==0) } // OnTransferGroupOwner() -message GroupOwnerTransferredTips{ +message GroupOwnerTransferredTips { GroupInfo group = 1; GroupMemberFullInfo opUser = 2; GroupMemberFullInfo newGroupOwner = 3; @@ -300,9 +297,8 @@ message GroupOwnerTransferredTips{ int64 operationTime = 5; } - // OnMemberKicked() -message MemberKickedTips{ +message MemberKickedTips { GroupInfo group = 1; GroupMemberFullInfo opUser = 2; repeated GroupMemberFullInfo kickedUserList = 3; @@ -310,7 +306,7 @@ message MemberKickedTips{ } // OnMemberInvited() -message MemberInvitedTips{ +message MemberInvitedTips { GroupInfo group = 1; GroupMemberFullInfo opUser = 2; repeated GroupMemberFullInfo invitedUserList = 3; @@ -318,19 +314,19 @@ message MemberInvitedTips{ } //Actively join the group -message MemberEnterTips{ +message MemberEnterTips { GroupInfo group = 1; GroupMemberFullInfo entrantUser = 2; int64 operationTime = 3; } -message GroupDismissedTips{ +message GroupDismissedTips { GroupInfo group = 1; GroupMemberFullInfo opUser = 2; int64 operationTime = 3; } -message GroupMemberMutedTips{ +message GroupMemberMutedTips { GroupInfo group = 1; GroupMemberFullInfo opUser = 2; int64 operationTime = 3; @@ -338,26 +334,26 @@ message GroupMemberMutedTips{ uint32 mutedSeconds = 5; } -message GroupMemberCancelMutedTips{ +message GroupMemberCancelMutedTips { GroupInfo group = 1; GroupMemberFullInfo opUser = 2; int64 operationTime = 3; GroupMemberFullInfo mutedUser = 4; } -message GroupMutedTips{ +message GroupMutedTips { GroupInfo group = 1; GroupMemberFullInfo opUser = 2; int64 operationTime = 3; } -message GroupCancelMutedTips{ +message GroupCancelMutedTips { GroupInfo group = 1; GroupMemberFullInfo opUser = 2; int64 operationTime = 3; } -message GroupMemberInfoSetTips{ +message GroupMemberInfoSetTips { GroupInfo group = 1; GroupMemberFullInfo opUser = 2; int64 operationTime = 3; @@ -366,64 +362,61 @@ message GroupMemberInfoSetTips{ //////////////////////friend///////////////////// -message FriendApplication{ +message FriendApplication { int64 addTime = 1; string addSource = 2; string addWording = 3; } -message FromToUserID{ +message FromToUserID { string fromUserID = 1; string toUserID = 2; } //FromUserID apply to add ToUserID -message FriendApplicationTips{ - FromToUserID fromToUserID = 1; //from:发起者; to:接收者 +message FriendApplicationTips { + FromToUserID fromToUserID = 1; //from:sender; to:receiver } //FromUserID accept or reject ToUserID -message FriendApplicationApprovedTips{ - FromToUserID fromToUserID = 1; //from:同意者;to:请求发起者 +message FriendApplicationApprovedTips { + FromToUserID fromToUserID = 1; //from: approver; to: requester string handleMsg = 2; } //FromUserID accept or reject ToUserID -message FriendApplicationRejectedTips{ - FromToUserID fromToUserID = 1; //from:拒绝者;to:请求发起者 +message FriendApplicationRejectedTips { + FromToUserID fromToUserID = 1; //from: rejecter; to: requester string handleMsg = 2; } - +} // FromUserID Added a friend ToUserID -message FriendAddedTips{ +message FriendAddedTips { FriendInfo friend = 1; int64 operationTime = 2; - PublicUserInfo opUser = 3; //who do this - + PublicUserInfo opUser = 3; //who do this } // FromUserID deleted a friend ToUserID -message FriendDeletedTips{ +message FriendDeletedTips { FromToUserID fromToUserID = 1; //from:owner; to:friend } - - -message BlackAddedTips{ +message BlackAddedTips { FromToUserID fromToUserID = 1; //from:owner; to:black } -message BlackDeletedTips{ +message BlackDeletedTips { FromToUserID fromToUserID = 1; //from:owner; to:black } -message FriendInfoChangedTips{ +message FriendInfoChangedTips { FromToUserID fromToUserID = 1; //from:changed; to:friend } //////////////////////user///////////////////// -message UserInfoUpdatedTips{ +message UserInfoUpdatedTips { string userID = 1; } @@ -447,12 +440,12 @@ message UserCommandDeleteTips { } //////////////////////conversation///////////////////// -message ConversationUpdateTips{ +message ConversationUpdateTips { string userID = 1; repeated string conversationIDList = 2; } -message ConversationSetPrivateTips{ +message ConversationSetPrivateTips { string recvID = 1; string sendID = 2; bool isPrivate = 3; @@ -475,14 +468,13 @@ message seqs { repeated int64 seqs = 1; } -message DeleteMessageTips{ +message DeleteMessageTips { string opUserID = 1; string userID = 2; repeated int64 seqs = 3; } - -message RevokeMsgTips{ +message RevokeMsgTips { string revokerUserID = 1; string clientMsgID = 2; int64 revokeTime = 3; @@ -492,19 +484,18 @@ message RevokeMsgTips{ bool isAdminRevoke = 8; } - message MessageRevokedContent { - string revokerID = 1; - int32 revokerRole = 2; - string clientMsgID = 3; - string revokerNickname = 4; - int64 revokeTime = 5; - int64 sourceMessageSendTime = 6; - string sourceMessageSendID = 7; - string sourceMessageSenderNickname = 8; - int32 sessionType = 10; - int64 seq = 11; - string ex = 12; + string revokerID = 1; + int32 revokerRole = 2; + string clientMsgID = 3; + string revokerNickname = 4; + int64 revokeTime = 5; + int64 sourceMessageSendTime = 6; + string sourceMessageSendID = 7; + string sourceMessageSenderNickname = 8; + int32 sessionType = 10; + int64 seq = 11; + string ex = 12; } message ClearConversationTips { @@ -513,7 +504,7 @@ message ClearConversationTips { } message DeleteMsgsTips { - string userID = 1; + string userID = 1; string conversationID = 2; repeated int64 seqs = 3; } @@ -525,15 +516,13 @@ message MarkAsReadTips { int64 hasReadSeq = 4; } - message SetAppBackgroundStatusReq { string userID = 1; bool isBackground = 2; } -message SetAppBackgroundStatusResp { -} -message ProcessUserCommand{ +message SetAppBackgroundStatusResp {} +message ProcessUserCommand { string userID = 1; int32 type = 2; int64 createTime = 3; @@ -545,7 +534,7 @@ message RequestPagination { int32 pageNumber = 1; int32 showNumber = 2; } -message FriendsInfoUpdateTips{ +message FriendsInfoUpdateTips { FromToUserID fromToUserID = 1; repeated string friendIDs = 2; } diff --git a/tools/check-component/main.go b/tools/check-component/main.go index cc3937baa..ab7676a16 100644 --- a/tools/check-component/main.go +++ b/tools/check-component/main.go @@ -24,7 +24,6 @@ import ( "github.com/openimsdk/chat/pkg/common/cmd" "github.com/openimsdk/chat/pkg/common/config" "github.com/openimsdk/chat/pkg/common/imapi" - constantpb "github.com/openimsdk/protocol/constant" "github.com/openimsdk/tools/db/mongoutil" "github.com/openimsdk/tools/db/redisutil" "github.com/openimsdk/tools/discovery/etcd" @@ -58,7 +57,7 @@ func CheckRedis(ctx context.Context, config *config.Redis) error { func CheckOpenIM(ctx context.Context, apiURL, secret, adminUserID string) error { imAPI := imapi.New(apiURL, secret, adminUserID) - _, err := imAPI.UserToken(mcontext.SetOperationID(ctx, "CheckOpenIM"+idutil.OperationIDGenerator()), adminUserID, constantpb.AdminPlatformID) + _, err := imAPI.GetAdminToken(mcontext.SetOperationID(ctx, "CheckOpenIM"+idutil.OperationIDGenerator()), adminUserID) return err } diff --git a/version/version/version b/version/version/version new file mode 100644 index 000000000..b9268dae2 --- /dev/null +++ b/version/version/version @@ -0,0 +1 @@ +1.8.1 \ No newline at end of file diff --git a/version/version/version.go b/version/version/version.go new file mode 100644 index 000000000..23b3a82f5 --- /dev/null +++ b/version/version/version.go @@ -0,0 +1,6 @@ +package version + +import _ "embed" + +//go:embed version +var Version string From af4ec6b8f73b61fdc28d6d0f7a3268d87188377e Mon Sep 17 00:00:00 2001 From: chao <48119764+withchao@users.noreply.github.com> Date: Mon, 28 Oct 2024 17:20:01 +0800 Subject: [PATCH 03/36] fix: errors caused by too many tokens (#608) * fix: too many tokens * fix: too many tokens * fix: too many tokens --- internal/api/mw/mw.go | 44 +---------- internal/rpc/admin/start.go | 10 +-- internal/rpc/admin/token.go | 1 - pkg/common/db/cache/token.go | 103 ++++++++++++++++++------- pkg/common/db/database/admin.go | 18 +---- pkg/common/tokenverify/token_verify.go | 15 ++++ 6 files changed, 103 insertions(+), 88 deletions(-) diff --git a/internal/api/mw/mw.go b/internal/api/mw/mw.go index 8f8bb2a4c..fa1092438 100644 --- a/internal/api/mw/mw.go +++ b/internal/api/mw/mw.go @@ -20,7 +20,6 @@ import ( "github.com/gin-gonic/gin" "github.com/openimsdk/chat/pkg/common/constant" "github.com/openimsdk/chat/pkg/protocol/admin" - constantpb "github.com/openimsdk/protocol/constant" "github.com/openimsdk/tools/apiresp" "github.com/openimsdk/tools/errs" ) @@ -56,74 +55,37 @@ func (o *MW) parseTokenType(c *gin.Context, userType int32) (string, string, err return userID, token, nil } -func (o *MW) isValidToken(c *gin.Context, userID string, token string) error { - resp, err := o.client.GetUserToken(c, &admin.GetUserTokenReq{UserID: userID}) - if err != nil { - return err - } - if len(resp.TokensMap) == 0 { - return errs.ErrTokenExpired.Wrap() - } - if v, ok := resp.TokensMap[token]; ok { - switch v { - case constantpb.NormalToken: - case constantpb.KickedToken: - return errs.ErrTokenExpired.Wrap() - default: - return errs.ErrTokenUnknown.Wrap() - } - } else { - return errs.ErrTokenExpired.Wrap() - } - return nil -} - func (o *MW) setToken(c *gin.Context, userID string, userType int32) { SetToken(c, userID, userType) } func (o *MW) CheckToken(c *gin.Context) { - userID, userType, token, err := o.parseToken(c) + userID, userType, _, err := o.parseToken(c) if err != nil { c.Abort() apiresp.GinError(c, err) return } - if err := o.isValidToken(c, userID, token); err != nil { - c.Abort() - apiresp.GinError(c, err) - return - } o.setToken(c, userID, userType) } func (o *MW) CheckAdmin(c *gin.Context) { - userID, token, err := o.parseTokenType(c, constant.AdminUser) + userID, _, err := o.parseTokenType(c, constant.AdminUser) if err != nil { c.Abort() apiresp.GinError(c, err) return } - if err := o.isValidToken(c, userID, token); err != nil { - c.Abort() - apiresp.GinError(c, err) - return - } o.setToken(c, userID, constant.AdminUser) } func (o *MW) CheckUser(c *gin.Context) { - userID, token, err := o.parseTokenType(c, constant.NormalUser) + userID, _, err := o.parseTokenType(c, constant.NormalUser) if err != nil { c.Abort() apiresp.GinError(c, err) return } - if err := o.isValidToken(c, userID, token); err != nil { - c.Abort() - apiresp.GinError(c, err) - return - } o.setToken(c, userID, constant.NormalUser) } diff --git a/internal/rpc/admin/start.go b/internal/rpc/admin/start.go index 54de3be3d..d08c31a78 100644 --- a/internal/rpc/admin/start.go +++ b/internal/rpc/admin/start.go @@ -47,7 +47,11 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg return err } var srv adminServer - srv.Database, err = database.NewAdminDatabase(mgocli, rdb) + srv.Token = &tokenverify.Token{ + Expires: time.Duration(config.RpcConfig.TokenPolicy.Expire) * time.Hour * 24, + Secret: config.RpcConfig.Secret, + } + srv.Database, err = database.NewAdminDatabase(mgocli, rdb, srv.Token) if err != nil { return err } @@ -56,10 +60,6 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg return err } srv.Chat = chatClient.NewChatClient(chat.NewChatClient(conn)) - srv.Token = &tokenverify.Token{ - Expires: time.Duration(config.RpcConfig.TokenPolicy.Expire) * time.Hour * 24, - Secret: config.RpcConfig.Secret, - } if err := srv.initAdmin(ctx, config.Share.ChatAdmin, config.Share.OpenIM.AdminUserID); err != nil { return err } diff --git a/internal/rpc/admin/token.go b/internal/rpc/admin/token.go index dc7fa1918..57e81d6a7 100644 --- a/internal/rpc/admin/token.go +++ b/internal/rpc/admin/token.go @@ -26,7 +26,6 @@ import ( func (o *adminServer) CreateToken(ctx context.Context, req *adminpb.CreateTokenReq) (*adminpb.CreateTokenResp, error) { token, expire, err := o.Token.CreateToken(req.UserID, req.UserType) - if err != nil { return nil, err } diff --git a/pkg/common/db/cache/token.go b/pkg/common/db/cache/token.go index a57571ebc..3ad6b6ca6 100644 --- a/pkg/common/db/cache/token.go +++ b/pkg/common/db/cache/token.go @@ -16,8 +16,9 @@ package cache import ( "context" - + "github.com/openimsdk/chat/pkg/common/tokenverify" "github.com/openimsdk/tools/utils/stringutil" + "sort" "time" "github.com/openimsdk/tools/errs" @@ -25,44 +26,24 @@ import ( ) const ( - chatToken = "CHAT_UID_TOKEN_STATUS:" + chatToken = "CHAT_UID_TOKEN_STATUS:" + userMaxTokenNum = 10 ) type TokenInterface interface { - AddTokenFlag(ctx context.Context, userID string, token string, flag int) error - AddTokenFlagNXEx(ctx context.Context, userID string, token string, flag int, expire time.Duration) (bool, error) + SetTokenExpire(ctx context.Context, userID string, token string, expire time.Duration) error GetTokensWithoutError(ctx context.Context, userID string) (map[string]int32, error) DeleteTokenByUid(ctx context.Context, userID string) error } type TokenCacheRedis struct { + token *tokenverify.Token rdb redis.UniversalClient accessExpire int64 } -func NewTokenInterface(rdb redis.UniversalClient) *TokenCacheRedis { - return &TokenCacheRedis{rdb: rdb} -} - -func (t *TokenCacheRedis) AddTokenFlag(ctx context.Context, userID string, token string, flag int) error { - key := chatToken + userID - return errs.Wrap(t.rdb.HSet(ctx, key, token, flag).Err()) -} - -func (t *TokenCacheRedis) AddTokenFlagNXEx(ctx context.Context, userID string, token string, flag int, expire time.Duration) (bool, error) { - key := chatToken + userID - isSet, err := t.rdb.HSetNX(ctx, key, token, flag).Result() - if err != nil { - return false, errs.Wrap(err) - } - if !isSet { - // key already exists - return false, nil - } - if err = t.rdb.Expire(ctx, key, expire).Err(); err != nil { - return false, errs.Wrap(err) - } - return isSet, nil +func NewTokenInterface(rdb redis.UniversalClient, token *tokenverify.Token) *TokenCacheRedis { + return &TokenCacheRedis{rdb: rdb, token: token} } func (t *TokenCacheRedis) GetTokensWithoutError(ctx context.Context, userID string) (map[string]int32, error) { @@ -82,3 +63,71 @@ func (t *TokenCacheRedis) DeleteTokenByUid(ctx context.Context, userID string) e key := chatToken + userID return errs.Wrap(t.rdb.Del(ctx, key).Err()) } + +func (t *TokenCacheRedis) SetTokenExpire(ctx context.Context, userID string, token string, expire time.Duration) error { + key := chatToken + userID + if err := t.rdb.HSet(ctx, key, token, "0").Err(); err != nil { + return errs.Wrap(err) + } + if err := t.rdb.Expire(ctx, key, expire).Err(); err != nil { + return errs.Wrap(err) + } + mm, err := t.rdb.HGetAll(ctx, key).Result() + if err != nil { + return errs.Wrap(err) + } + if len(mm) <= 1 { + return nil + } + var ( + fields []string + ts tokenTimes + ) + now := time.Now() + for k := range mm { + if k == token { + continue + } + val := t.token.GetExpire(k) + if val.IsZero() || val.Before(now) { + fields = append(fields, k) + } else { + ts = append(ts, tokenTime{Token: k, Time: val}) + } + } + var sorted bool + var index int + for i := len(mm) - len(fields); i > userMaxTokenNum; i-- { + if !sorted { + sorted = true + sort.Sort(ts) + } + fields = append(fields, ts[index].Token) + index++ + } + if len(fields) > 0 { + if err := t.rdb.HDel(ctx, key, fields...).Err(); err != nil { + return errs.Wrap(err) + } + } + return nil +} + +type tokenTime struct { + Token string + Time time.Time +} + +type tokenTimes []tokenTime + +func (t tokenTimes) Len() int { + return len(t) +} + +func (t tokenTimes) Less(i, j int) bool { + return t[i].Time.Before(t[j].Time) +} + +func (t tokenTimes) Swap(i, j int) { + t[i], t[j] = t[j], t[i] +} diff --git a/pkg/common/db/database/admin.go b/pkg/common/db/database/admin.go index 820864df1..bf4859772 100644 --- a/pkg/common/db/database/admin.go +++ b/pkg/common/db/database/admin.go @@ -16,10 +16,10 @@ package database import ( "context" + "github.com/openimsdk/chat/pkg/common/tokenverify" "time" "github.com/openimsdk/chat/pkg/common/db/cache" - "github.com/openimsdk/protocol/constant" "github.com/openimsdk/tools/db/mongoutil" "github.com/openimsdk/tools/db/pagination" "github.com/openimsdk/tools/db/tx" @@ -80,7 +80,7 @@ type AdminDatabaseInterface interface { DeleteToken(ctx context.Context, userID string) error } -func NewAdminDatabase(cli *mongoutil.Client, rdb redis.UniversalClient) (AdminDatabaseInterface, error) { +func NewAdminDatabase(cli *mongoutil.Client, rdb redis.UniversalClient, token *tokenverify.Token) (AdminDatabaseInterface, error) { a, err := admin.NewAdmin(cli.GetDB()) if err != nil { return nil, err @@ -128,7 +128,7 @@ func NewAdminDatabase(cli *mongoutil.Client, rdb redis.UniversalClient) (AdminDa registerAddGroup: registerAddGroup, applet: applet, clientConfig: clientConfig, - cache: cache.NewTokenInterface(rdb), + cache: cache.NewTokenInterface(rdb, token), }, nil } @@ -327,17 +327,7 @@ func (o *AdminDatabase) GetLimitUserLoginIP(ctx context.Context, userID string, } func (o *AdminDatabase) CacheToken(ctx context.Context, userID string, token string, expire time.Duration) error { - isSet, err := o.cache.AddTokenFlagNXEx(ctx, userID, token, constant.NormalToken, expire) - if err != nil { - return err - } - if !isSet { - // already exists, update - if err = o.cache.AddTokenFlag(ctx, userID, token, constant.NormalToken); err != nil { - return err - } - } - return nil + return o.cache.SetTokenExpire(ctx, userID, token, expire) } func (o *AdminDatabase) GetTokens(ctx context.Context, userID string) (map[string]int32, error) { diff --git a/pkg/common/tokenverify/token_verify.go b/pkg/common/tokenverify/token_verify.go index 3c35ffa71..59521873f 100644 --- a/pkg/common/tokenverify/token_verify.go +++ b/pkg/common/tokenverify/token_verify.go @@ -109,6 +109,21 @@ func (t *Token) GetToken(token string) (string, int32, error) { return userID, userType, nil } +func (t *Token) GetExpire(token string) time.Time { + val, err := jwt.ParseWithClaims(token, &claims{}, t.secret()) + if err != nil { + return time.Time{} + } + c, ok := val.Claims.(*claims) + if !ok { + return time.Time{} + } + if c.ExpiresAt == nil { + return time.Time{} + } + return c.ExpiresAt.Time +} + //func (t *Token) GetAdminToken(token string) (string, error) { // userID, userType, err := getToken(token) // if err != nil { From 7468fd43c7d56458346df1667fe899aa1dd0f034 Mon Sep 17 00:00:00 2001 From: AerisVibe <166510977+AerisVibe@users.noreply.github.com> Date: Mon, 25 Nov 2024 11:12:38 +0800 Subject: [PATCH 04/36] fix bug:invalid go version '1.21.2' : must match format 1.23 (#527) Co-authored-by: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Co-authored-by: Monet Lee --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 2b84c4af7..ec55a64c3 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/openimsdk/chat -go 1.21.2 +go 1.21 require ( github.com/gin-gonic/gin v1.9.1 From bfe1c3c625544092d2d46e76addfab1e256b15ff Mon Sep 17 00:00:00 2001 From: icey-yu <119291641+icey-yu@users.noreply.github.com> Date: Wed, 16 Oct 2024 11:29:19 +0800 Subject: [PATCH 05/36] Change account logic and add allowRegister config (#583) * cherry-pick * chore: protocol * chore: user register and update * chore: credential * fix: cherry-pick * chore: user register and update * feat: register pb * fix: cherry-pick * feat: login * feat: check param * fix: check param * fix: protocol * fix: cherry-pick * fix: cherry-pick --- .github/workflows/docker-buildx.bak | 19 +- config/chat-rpc-chat.yml | 2 + go.mod | 2 +- go.sum | 4 +- internal/api/admin/admin.go | 31 +- internal/api/admin/start.go | 4 + internal/rpc/chat/callback.go | 2 +- internal/rpc/chat/login.go | 136 +++--- internal/rpc/chat/password.go | 4 +- internal/rpc/chat/register.go | 15 + internal/rpc/chat/start.go | 2 + internal/rpc/chat/update.go | 55 +++ internal/rpc/chat/user.go | 309 +++++++----- internal/rpc/chat/utils.go | 85 +++- pkg/common/config/config.go | 1 + pkg/common/constant/constant.go | 32 +- pkg/common/db/database/chat.go | 82 ++-- pkg/common/db/model/chat/credential.go | 142 ++++++ pkg/common/db/table/chat/attribute.go | 14 - pkg/common/db/table/chat/credential.go | 32 ++ pkg/common/imapi/caller.go | 14 - pkg/email/mail_test.go | 124 ++--- pkg/protocol/chat/chat.pb.go | 651 ++++++++++++++++++------- pkg/protocol/chat/chat.proto | 18 + pkg/protocol/gen.cmd | 5 + pkg/protocol/sdkws/sdkws.proto | 1 - 26 files changed, 1201 insertions(+), 585 deletions(-) create mode 100644 internal/rpc/chat/register.go create mode 100644 pkg/common/db/model/chat/credential.go create mode 100644 pkg/common/db/table/chat/credential.go diff --git a/.github/workflows/docker-buildx.bak b/.github/workflows/docker-buildx.bak index b40aa6fef..cbd6440e4 100644 --- a/.github/workflows/docker-buildx.bak +++ b/.github/workflows/docker-buildx.bak @@ -1,17 +1,3 @@ -# Copyright © 2023 OpenIM open source community. 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. - name: Docker Buildx Images CI on: @@ -40,11 +26,12 @@ jobs: install: true - name: Cache Docker layers - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: /tmp/.buildx-cache key: ${{ runner.os }}-buildx-${{ github.sha }} - restore-keys: ${{ runner.os }}-buildx- + restore-keys: | + ${{ runner.os }}-buildx- - name: Log in to GitHub Container Registry uses: docker/login-action@v3 diff --git a/config/chat-rpc-chat.yml b/config/chat-rpc-chat.yml index d015ad63f..329cfd51f 100644 --- a/config/chat-rpc-chat.yml +++ b/config/chat-rpc-chat.yml @@ -33,3 +33,5 @@ liveKit: url: "ws://127.0.0.1:7880" # LIVEKIT_URL, LiveKit server address and port key: "APIGPW3gnFTzqHH" secret: "23ztfSqsfQ8hKkHzHTl3Z4bvaxro0snjk5jwbp5p6Q3" + +allowRegister: true diff --git a/go.mod b/go.mod index ec55a64c3..415298ac2 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/mitchellh/mapstructure v1.5.0 github.com/openimsdk/gomake v0.0.14-alpha.5 github.com/openimsdk/protocol v0.0.72 - github.com/openimsdk/tools v0.0.50-alpha.15 + github.com/openimsdk/tools v0.0.50-alpha.20 github.com/redis/go-redis/v9 v9.5.1 github.com/spf13/cobra v1.8.0 github.com/spf13/viper v1.18.2 diff --git a/go.sum b/go.sum index a4f7c8ac8..b6f181fe2 100644 --- a/go.sum +++ b/go.sum @@ -189,8 +189,8 @@ github.com/openimsdk/gomake v0.0.14-alpha.5 h1:VY9c5x515lTfmdhhPjMvR3BBRrRquAUCF github.com/openimsdk/gomake v0.0.14-alpha.5/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI= github.com/openimsdk/protocol v0.0.72 h1:K+vslwaR7lDXyBzb07UuEQITaqsgighz7NyXVIWsu6A= github.com/openimsdk/protocol v0.0.72/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8= -github.com/openimsdk/tools v0.0.50-alpha.15 h1:HV9aKZ4vvCZCGG4wFDsgUONkkdJeCcrFNn3BT52nUVQ= -github.com/openimsdk/tools v0.0.50-alpha.15/go.mod h1:h1cYmfyaVtgFbKmb1Cfsl8XwUOMTt8ubVUQrdGtsUh4= +github.com/openimsdk/tools v0.0.50-alpha.20 h1:TUCZOwaea983Qj1MCbiGZUBlwBkTMwTF9SLS0WQcsJs= +github.com/openimsdk/tools v0.0.50-alpha.20/go.mod h1:h1cYmfyaVtgFbKmb1Cfsl8XwUOMTt8ubVUQrdGtsUh4= github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pion/datachannel v1.5.5 h1:10ef4kwdjije+M9d7Xm9im2Y3O6A6ccQb0zcqZcJew8= diff --git a/internal/api/admin/admin.go b/internal/api/admin/admin.go index 7e0a44893..6bc4b921c 100644 --- a/internal/api/admin/admin.go +++ b/internal/api/admin/admin.go @@ -1,17 +1,3 @@ -// Copyright © 2023 OpenIM open source community. 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 admin import ( @@ -72,7 +58,7 @@ func (o *Api) AdminLogin(c *gin.Context) { return } imAdminUserID := o.GetDefaultIMAdminUserID() - imToken, err := o.imApiCaller.GetAdminToken(c, imAdminUserID) + imToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) if err != nil { apiresp.GinError(c, err) return @@ -173,6 +159,12 @@ func (o *Api) AddUserAccount(c *gin.Context) { return } + if resp, err := o.adminClient.FindDefaultFriend(c, &admin.FindDefaultFriendReq{}); err == nil { + _ = o.imApiCaller.ImportFriend(c, req.User.UserID, resp.UserIDs) + } + if resp, err := o.adminClient.FindDefaultGroup(c, &admin.FindDefaultGroupReq{}); err == nil { + _ = o.imApiCaller.InviteToGroup(c, req.User.UserID, resp.GroupIDs) + } apiresp.GinSuccess(c, nil) } @@ -547,6 +539,7 @@ func (o *Api) registerChatUser(ctx context.Context, ip string, users []*chat.Reg if err = o.imApiCaller.RegisterUser(ctx, []*sdkws.UserInfo{userInfo}); err != nil { return err } + if resp, err := o.adminClient.FindDefaultFriend(ctx, &admin.FindDefaultFriendReq{}); err == nil { _ = o.imApiCaller.ImportFriend(ctx, respRegisterUser.UserID, resp.UserIDs) } @@ -571,3 +564,11 @@ func (o *Api) BatchImportTemplate(c *gin.Context) { c.Header("ETag", md5Val) c.Data(http.StatusOK, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", config.ImportTemplate) } + +func (o *Api) SetAllowRegister(c *gin.Context) { + a2r.Call(chat.ChatClient.SetAllowRegister, o.chatClient, c) +} + +func (o *Api) GetAllowRegister(c *gin.Context) { + a2r.Call(chat.ChatClient.GetAllowRegister, o.chatClient, c) +} diff --git a/internal/api/admin/start.go b/internal/api/admin/start.go index 05a1799b3..fc53c94f8 100644 --- a/internal/api/admin/start.go +++ b/internal/api/admin/start.go @@ -81,6 +81,10 @@ func SetAdminRoute(router gin.IRouter, admin *Api, mw *chatmw.MW) { importGroup.POST("/xlsx", mw.CheckAdmin, admin.ImportUserByXlsx) importGroup.GET("/xlsx", admin.BatchImportTemplate) + allowRegisterGroup := router.Group("/user/allow_register", mw.CheckAdmin) + allowRegisterGroup.POST("/get", admin.GetAllowRegister) + allowRegisterGroup.POST("/set", admin.SetAllowRegister) + defaultRouter := router.Group("/default", mw.CheckAdmin) defaultUserRouter := defaultRouter.Group("/user") defaultUserRouter.POST("/add", admin.AddDefaultFriend) // Add default friend at registration diff --git a/internal/rpc/chat/callback.go b/internal/rpc/chat/callback.go index b355d7660..d4bfe5558 100644 --- a/internal/rpc/chat/callback.go +++ b/internal/rpc/chat/callback.go @@ -47,7 +47,7 @@ func (o *chatSvr) OpenIMCallback(ctx context.Context, req *chat.OpenIMCallbackRe if err := json.Unmarshal([]byte(req.Body), &data); err != nil { return nil, errs.Wrap(err) } - user, err := o.Database.GetAttribute(ctx, data.ToUserID) + user, err := o.Database.TakeAttributeByUserID(ctx, data.ToUserID) if err != nil { return nil, err } diff --git a/internal/rpc/chat/login.go b/internal/rpc/chat/login.go index 59990302d..e672ccddf 100644 --- a/internal/rpc/chat/login.go +++ b/internal/rpc/chat/login.go @@ -1,17 +1,3 @@ -// Copyright © 2023 OpenIM open source community. 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 chat import ( @@ -50,7 +36,7 @@ func (o *chatSvr) SendVerifyCode(ctx context.Context, req *chat.SendVerifyCodeRe if req.AreaCode == "" || req.PhoneNumber == "" { return nil, errs.ErrArgs.WrapMsg("area code or phone number is empty") } - if req.AreaCode[0] != '+' { + if !strings.HasPrefix(req.AreaCode, "+") { req.AreaCode = "+" + req.AreaCode } if _, err := strconv.ParseUint(req.AreaCode[1:], 10, 64); err != nil { @@ -59,22 +45,10 @@ func (o *chatSvr) SendVerifyCode(ctx context.Context, req *chat.SendVerifyCodeRe if _, err := strconv.ParseUint(req.PhoneNumber, 10, 64); err != nil { return nil, errs.ErrArgs.WrapMsg("phone number must be number") } - _, err := o.Database.TakeAttributeByPhone(ctx, req.AreaCode, req.PhoneNumber) - if err == nil { - return nil, eerrs.ErrPhoneAlreadyRegister.WrapMsg("phone already register") - } else if !dbutil.IsDBNotFound(err) { - return nil, err - } } else { if err := chat.EmailCheck(req.Email); err != nil { return nil, errs.ErrArgs.WrapMsg("email must be right") } - _, err := o.Database.TakeAttributeByEmail(ctx, req.Email) - if err == nil { - return nil, eerrs.ErrEmailAlreadyRegister.WrapMsg("email already register") - } else if !dbutil.IsDBNotFound(err) { - return nil, err - } } conf, err := o.Admin.GetConfig(ctx) if err != nil { @@ -245,16 +219,14 @@ func (o *chatSvr) RegisterUser(ctx context.Context, req *chat.RegisterUserReq) ( if err != nil { return nil, err } - if req.User == nil { - return nil, errs.ErrArgs.WrapMsg("user is nil") - } - if req.User.Email == "" { - if (req.User.AreaCode == "" && req.User.PhoneNumber != "") || (req.User.AreaCode != "" && req.User.PhoneNumber == "") { - return nil, errs.ErrArgs.WrapMsg("area code or phone number error, no email provide") - } + if err = o.checkRegisterInfo(ctx, req.User, isAdmin); err != nil { + return nil, err } var usedInvitationCode bool if !isAdmin { + if !o.AllowRegister { + return nil, errs.ErrNoPermission.WrapMsg("register user is disabled") + } if req.User.UserID != "" { return nil, errs.ErrNoPermission.WrapMsg("only admin can set user id") } @@ -308,43 +280,39 @@ func (o *chatSvr) RegisterUser(ctx context.Context, req *chat.RegisterUserReq) ( return nil, err } } - var registerType int32 + var ( + credentials []*chatdb.Credential + registerType int32 + ) + if req.User.PhoneNumber != "" { - if req.User.AreaCode[0] != '+' { - req.User.AreaCode = "+" + req.User.AreaCode - } - if _, err := strconv.ParseUint(req.User.AreaCode[1:], 10, 64); err != nil { - return nil, errs.ErrArgs.WrapMsg("area code must be number") - } - if _, err := strconv.ParseUint(req.User.PhoneNumber, 10, 64); err != nil { - return nil, errs.ErrArgs.WrapMsg("phone number must be number") - } - _, err := o.Database.TakeAttributeByPhone(ctx, req.User.AreaCode, req.User.PhoneNumber) - if err == nil { - return nil, eerrs.ErrPhoneAlreadyRegister.Wrap() - } else if !dbutil.IsDBNotFound(err) { - return nil, err - } registerType = constant.PhoneRegister + credentials = append(credentials, &chatdb.Credential{ + UserID: req.User.UserID, + Account: BuildCredentialPhone(req.User.AreaCode, req.User.PhoneNumber), + Type: constant.CredentialPhone, + AllowChange: true, + }) } if req.User.Account != "" { - _, err := o.Database.TakeAttributeByAccount(ctx, req.User.Account) - if err == nil { - return nil, eerrs.ErrAccountAlreadyRegister.Wrap() - } else if !dbutil.IsDBNotFound(err) { - return nil, err - } + credentials = append(credentials, &chatdb.Credential{ + UserID: req.User.UserID, + Account: req.User.Account, + Type: constant.CredentialAccount, + AllowChange: true, + }) + registerType = constant.AccountRegister } if req.User.Email != "" { - _, err := o.Database.TakeAttributeByEmail(ctx, req.User.Email) registerType = constant.EmailRegister - if err == nil { - return nil, eerrs.ErrEmailAlreadyRegister.Wrap() - } else if !dbutil.IsDBNotFound(err) { - return nil, err - } + credentials = append(credentials, &chatdb.Credential{ + UserID: req.User.UserID, + Account: req.User.Email, + Type: constant.CredentialEmail, + AllowChange: true, + }) } register := &chatdb.Register{ UserID: req.User.UserID, @@ -362,6 +330,7 @@ func (o *chatSvr) RegisterUser(ctx context.Context, req *chat.RegisterUserReq) ( ChangeTime: register.CreateTime, CreateTime: register.CreateTime, } + attribute := &chatdb.Attribute{ UserID: req.User.UserID, Account: req.User.Account, @@ -379,7 +348,7 @@ func (o *chatSvr) RegisterUser(ctx context.Context, req *chat.RegisterUserReq) ( AllowAddFriend: constant.DefaultAllowAddFriend, RegisterType: registerType, } - if err := o.Database.RegisterUser(ctx, register, account, attribute); err != nil { + if err := o.Database.RegisterUser(ctx, register, account, attribute, credentials); err != nil { return nil, err } if usedInvitationCode { @@ -405,33 +374,42 @@ func (o *chatSvr) Login(ctx context.Context, req *chat.LoginReq) (*chat.LoginRes if req.Password == "" && req.VerifyCode == "" { return nil, errs.ErrArgs.WrapMsg("password or code must be set") } - var err error - var attribute *chatdb.Attribute - if req.Account != "" { - attribute, err = o.Database.GetAttributeByAccount(ctx, req.Account) - } else if req.PhoneNumber != "" { + if req.Password == "" { + return nil, errs.ErrArgs.WrapMsg("password must be set") + } + var ( + err error + credential *chatdb.Credential + acc string + ) + + switch { + case req.Account != "": + acc = req.Account + case req.PhoneNumber != "": if req.AreaCode == "" { return nil, errs.ErrArgs.WrapMsg("area code must") } - if req.AreaCode[0] != '+' { + if !strings.HasPrefix(req.AreaCode, "+") { req.AreaCode = "+" + req.AreaCode } if _, err := strconv.ParseUint(req.AreaCode[1:], 10, 64); err != nil { return nil, errs.ErrArgs.WrapMsg("area code must be number") } - attribute, err = o.Database.GetAttributeByPhone(ctx, req.AreaCode, req.PhoneNumber) - } else if req.Email != "" { - attribute, err = o.Database.GetAttributeByEmail(ctx, req.Email) - } else { - err = errs.ErrArgs.WrapMsg("account or phone number or email must be set") + acc = BuildCredentialPhone(req.AreaCode, req.PhoneNumber) + case req.Email != "": + acc = req.Email + default: + return nil, errs.ErrArgs.WrapMsg("account or phone number or email must be set") } + credential, err = o.Database.TakeCredentialByAccount(ctx, acc) if err != nil { if dbutil.IsDBNotFound(err) { return nil, eerrs.ErrAccountNotFound.WrapMsg("user unregistered") } return nil, err } - if err := o.Admin.CheckLogin(ctx, attribute.UserID, req.Ip); err != nil { + if err := o.Admin.CheckLogin(ctx, credential.UserID, req.Ip); err != nil { return nil, err } var verifyCodeID *string @@ -450,7 +428,7 @@ func (o *chatSvr) Login(ctx context.Context, req *chat.LoginReq) (*chat.LoginRes verifyCodeID = &id } } else { - account, err := o.Database.GetAccount(ctx, attribute.UserID) + account, err := o.Database.TakeAccount(ctx, credential.UserID) if err != nil { return nil, err } @@ -458,12 +436,12 @@ func (o *chatSvr) Login(ctx context.Context, req *chat.LoginReq) (*chat.LoginRes return nil, eerrs.ErrPassword.Wrap() } } - chatToken, err := o.Admin.CreateToken(ctx, attribute.UserID, constant.NormalUser) + chatToken, err := o.Admin.CreateToken(ctx, credential.UserID, constant.NormalUser) if err != nil { return nil, err } record := &chatdb.UserLoginRecord{ - UserID: attribute.UserID, + UserID: credential.UserID, LoginTime: time.Now(), IP: req.Ip, DeviceID: req.DeviceID, @@ -477,7 +455,7 @@ func (o *chatSvr) Login(ctx context.Context, req *chat.LoginReq) (*chat.LoginRes return nil, err } } - resp.UserID = attribute.UserID + resp.UserID = credential.UserID resp.ChatToken = chatToken.Token return resp, nil } diff --git a/internal/rpc/chat/password.go b/internal/rpc/chat/password.go index 6235a2df7..7c9657a0a 100644 --- a/internal/rpc/chat/password.go +++ b/internal/rpc/chat/password.go @@ -41,13 +41,13 @@ func (o *chatSvr) ResetPassword(ctx context.Context, req *chat.ResetPasswordReq) } if req.Email == "" { - attribute, err := o.Database.GetAttributeByPhone(ctx, req.AreaCode, req.PhoneNumber) + attribute, err := o.Database.TakeAttributeByPhone(ctx, req.AreaCode, req.PhoneNumber) if err != nil { return nil, err } err = o.Database.UpdatePasswordAndDeleteVerifyCode(ctx, attribute.UserID, req.Password, verifyCodeID) } else { - attribute, err := o.Database.GetAttributeByEmail(ctx, req.Email) + attribute, err := o.Database.TakeAttributeByEmail(ctx, req.Email) if err != nil { return nil, err } diff --git a/internal/rpc/chat/register.go b/internal/rpc/chat/register.go new file mode 100644 index 000000000..9eb610044 --- /dev/null +++ b/internal/rpc/chat/register.go @@ -0,0 +1,15 @@ +package chat + +import ( + "context" + "github.com/openimsdk/chat/pkg/protocol/chat" +) + +func (o *chatSvr) SetAllowRegister(ctx context.Context, req *chat.SetAllowRegisterReq) (*chat.SetAllowRegisterResp, error) { + o.AllowRegister = req.AllowRegister + return &chat.SetAllowRegisterResp{}, nil +} + +func (o *chatSvr) GetAllowRegister(ctx context.Context, req *chat.GetAllowRegisterReq) (*chat.GetAllowRegisterResp, error) { + return &chat.GetAllowRegisterResp{AllowRegister: o.AllowRegister}, nil +} diff --git a/internal/rpc/chat/start.go b/internal/rpc/chat/start.go index 71939dd54..901b2c5dd 100644 --- a/internal/rpc/chat/start.go +++ b/internal/rpc/chat/start.go @@ -68,6 +68,7 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg Len: config.RpcConfig.VerifyCode.Len, } srv.Livekit = rtc.NewLiveKit(config.RpcConfig.LiveKit.Key, config.RpcConfig.LiveKit.Secret, config.RpcConfig.LiveKit.URL) + srv.AllowRegister = config.RpcConfig.AllowRegister chat.RegisterChatServer(server, &srv) return nil } @@ -80,6 +81,7 @@ type chatSvr struct { Code verifyCode Livekit *rtc.LiveKit ChatAdminUserID string + AllowRegister bool } func (o *chatSvr) WithAdminUser(ctx context.Context) context.Context { diff --git a/internal/rpc/chat/update.go b/internal/rpc/chat/update.go index 4579f1c3e..8f69de2f2 100644 --- a/internal/rpc/chat/update.go +++ b/internal/rpc/chat/update.go @@ -15,6 +15,8 @@ package chat import ( + "github.com/openimsdk/chat/pkg/common/constant" + chatdb "github.com/openimsdk/chat/pkg/common/db/table/chat" "time" "github.com/openimsdk/tools/errs" @@ -68,3 +70,56 @@ func ToDBAttributeUpdate(req *chat.UpdateUserInfoReq) (map[string]any, error) { //} return update, nil } + +func ToDBCredentialUpdate(req *chat.UpdateUserInfoReq, allowChange bool) ([]*chatdb.Credential, []*chatdb.Credential, error) { + update := make([]*chatdb.Credential, 0) + del := make([]*chatdb.Credential, 0) + if req.Account != nil { + if req.Account.GetValue() == "" { + del = append(del, &chatdb.Credential{ + UserID: req.UserID, + Type: constant.CredentialAccount, + }) + } else { + update = append(update, &chatdb.Credential{ + UserID: req.UserID, + Account: req.Account.GetValue(), + Type: constant.CredentialAccount, + AllowChange: allowChange, + }) + } + } + + if req.Email != nil { + if req.Email.GetValue() == "" { + del = append(del, &chatdb.Credential{ + UserID: req.UserID, + Type: constant.CredentialEmail, + }) + } else { + update = append(update, &chatdb.Credential{ + UserID: req.UserID, + Account: req.Account.GetValue(), + Type: constant.CredentialEmail, + AllowChange: allowChange, + }) + } + } + if req.PhoneNumber != nil { + if req.PhoneNumber.GetValue() == "" { + del = append(del, &chatdb.Credential{ + UserID: req.UserID, + Type: constant.CredentialPhone, + }) + } else { + update = append(update, &chatdb.Credential{ + UserID: req.UserID, + Account: BuildCredentialPhone(req.AreaCode.GetValue(), req.PhoneNumber.GetValue()), + Type: constant.CredentialPhone, + AllowChange: allowChange, + }) + } + } + + return update, del, nil +} diff --git a/internal/rpc/chat/user.go b/internal/rpc/chat/user.go index ce789613a..057cc6d78 100644 --- a/internal/rpc/chat/user.go +++ b/internal/rpc/chat/user.go @@ -16,6 +16,12 @@ package chat import ( "context" + "errors" + "github.com/openimsdk/chat/pkg/eerrs" + "github.com/openimsdk/protocol/wrapperspb" + "github.com/openimsdk/tools/utils/stringutil" + "strconv" + "strings" "time" "github.com/openimsdk/chat/pkg/common/db/dbutil" @@ -27,83 +33,118 @@ import ( "github.com/openimsdk/chat/pkg/common/constant" "github.com/openimsdk/chat/pkg/common/mctx" - "github.com/openimsdk/chat/pkg/eerrs" "github.com/openimsdk/chat/pkg/protocol/chat" "github.com/openimsdk/tools/errs" ) func (o *chatSvr) checkUpdateInfo(ctx context.Context, req *chat.UpdateUserInfoReq) error { - attribute, err := o.Database.TakeAttributeByUserID(ctx, req.UserID) + if req.AreaCode != nil || req.PhoneNumber != nil { + if !(req.AreaCode != nil && req.PhoneNumber != nil) { + return errs.ErrArgs.WrapMsg("areaCode and phoneNumber must be set together") + } + if req.AreaCode.Value == "" || req.PhoneNumber.Value == "" { + if req.AreaCode.Value != req.PhoneNumber.Value { + return errs.ErrArgs.WrapMsg("areaCode and phoneNumber must be set together") + } + } + } + if req.UserID == "" { + return errs.ErrArgs.WrapMsg("user id is empty") + } + + credentials, err := o.Database.TakeCredentialsByUserID(ctx, req.UserID) if err != nil { return err + } else if len(credentials) == 0 { + return errs.ErrArgs.WrapMsg("user not found") } - checkEmail := func() error { - if req.Email == nil { - return nil - } - if req.Email.Value == attribute.Email { - req.Email = nil - return nil + var ( + credNum, delNum, addNum = len(credentials), 0, 0 + ) + + addFunc := func(s *wrapperspb.StringValue) { + if s != nil { + if s.Value != "" { + addNum++ + } } - if req.Email.Value == "" { - if !(attribute.Account != "" || (attribute.AreaCode != "" && attribute.PhoneNumber != "")) { - return errs.ErrArgs.WrapMsg("a login method must exist") + } + + for _, s := range []*wrapperspb.StringValue{req.Account, req.PhoneNumber, req.Email} { + addFunc(s) + } + + for _, credential := range credentials { + switch credential.Type { + case constant.CredentialAccount: + if req.Account != nil { + if req.Account.Value == credential.Account { + req.Account = nil + } else if req.Account.Value == "" { + delNum += 1 + } } - return nil - } else { - if _, err := o.Database.GetAttributeByEmail(ctx, req.Email.Value); err == nil { - return errs.ErrDuplicateKey.WrapMsg("email already exists") - } else if !dbutil.IsDBNotFound(err) { - return err + case constant.CredentialPhone: + if req.PhoneNumber != nil { + phoneAccount := BuildCredentialPhone(req.AreaCode.Value, req.PhoneNumber.Value) + if phoneAccount == credential.Account { + req.AreaCode = nil + req.PhoneNumber = nil + } else if req.PhoneNumber.Value == "" { + delNum += 1 + } + } + case constant.CredentialEmail: + if req.Email != nil { + if req.Email.Value == credential.Account { + req.Email = nil + } else if req.Email.Value == "" { + delNum += 1 + } } } - return nil } - checkPhone := func() error { - if req.AreaCode == nil { - return nil + + if addNum+credNum-delNum <= 0 { + return errs.ErrArgs.WrapMsg("a login method must exist") + } + + if req.PhoneNumber.GetValue() != "" { + if !strings.HasPrefix(req.AreaCode.GetValue(), "+") { + req.AreaCode.Value = "+" + req.AreaCode.Value } - if req.AreaCode.Value == attribute.AreaCode && req.PhoneNumber.Value == attribute.PhoneNumber { - req.AreaCode = nil - req.PhoneNumber = nil - return nil + if _, err := strconv.ParseUint(req.AreaCode.Value[1:], 10, 64); err != nil { + return errs.ErrArgs.WrapMsg("area code must be number") } - if req.AreaCode.Value == "" || req.PhoneNumber.Value == "" { - if attribute.Email == "" || attribute.Account == "" { - return errs.ErrArgs.WrapMsg("a login method must exist") - } - } else { - if _, err := o.Database.GetAttributeByPhone(ctx, req.AreaCode.Value, req.PhoneNumber.Value); err == nil { - return errs.ErrDuplicateKey.WrapMsg("phone number already exists") - } else if !dbutil.IsDBNotFound(err) { - return err - } + if _, err := strconv.ParseUint(req.PhoneNumber.GetValue(), 10, 64); err != nil { + return errs.ErrArgs.WrapMsg("phone number must be number") } - return nil - } - checkAccount := func() error { - if req.Account == nil { - return nil + _, err := o.Database.TakeCredentialByAccount(ctx, BuildCredentialPhone(req.AreaCode.GetValue(), req.PhoneNumber.GetValue())) + if err == nil { + return eerrs.ErrPhoneAlreadyRegister.Wrap() + } else if !dbutil.IsDBNotFound(err) { + return err } - if req.Account.Value == attribute.Account { - req.Account = nil - return nil + } + if req.Account.GetValue() != "" { + if !stringutil.IsAlphanumeric(req.Account.GetValue()) { + return errs.ErrArgs.WrapMsg("account must be alphanumeric") } - if req.Account.Value == "" { - if !(attribute.Email == "" && (attribute.AreaCode == "" || attribute.PhoneNumber == "")) { - return errs.ErrArgs.WrapMsg("a login method must exist") - } - } else { - if _, err := o.Database.GetAttributeByAccount(ctx, req.Account.Value); err == nil { - return errs.ErrDuplicateKey.WrapMsg("account already exists") - } else if !dbutil.IsDBNotFound(err) { - return err - } + _, err := o.Database.TakeCredentialByAccount(ctx, req.Account.GetValue()) + if err == nil { + return eerrs.ErrAccountAlreadyRegister.Wrap() + } else if !dbutil.IsDBNotFound(err) { + return err } - return nil } - for _, fn := range []func() error{checkEmail, checkPhone, checkAccount} { - if err := fn(); err != nil { + if req.Email.GetValue() != "" { + if !stringutil.IsValidEmail(req.Email.GetValue()) { + return errs.ErrArgs.WrapMsg("invalid email") + } + _, err := o.Database.TakeCredentialByAccount(ctx, req.Email.GetValue()) + if err == nil { + return eerrs.ErrAccountAlreadyRegister.Wrap() + } else if !dbutil.IsDBNotFound(err) { return err } } @@ -111,56 +152,39 @@ func (o *chatSvr) checkUpdateInfo(ctx context.Context, req *chat.UpdateUserInfoR } func (o *chatSvr) UpdateUserInfo(ctx context.Context, req *chat.UpdateUserInfoReq) (*chat.UpdateUserInfoResp, error) { - if req.AreaCode != nil || req.PhoneNumber != nil { - if !(req.AreaCode != nil && req.PhoneNumber != nil) { - return nil, errs.ErrArgs.WrapMsg("areaCode and phoneNumber must be set together") - } - if req.AreaCode.Value == "" || req.PhoneNumber.Value == "" { - if req.AreaCode.Value != req.PhoneNumber.Value { - return nil, errs.ErrArgs.WrapMsg("areaCode and phoneNumber must be set together") - } - } - } opUserID, userType, err := mctx.Check(ctx) if err != nil { return nil, err } - if req.UserID == "" { - return nil, errs.ErrArgs.WrapMsg("user id is empty") + + if err = o.checkUpdateInfo(ctx, req); err != nil { + return nil, err } + switch userType { case constant.NormalUser: - //if req.UserID == "" { - // req.UserID = opUserID - //} + if req.RegisterType != nil { + return nil, errs.ErrNoPermission.WrapMsg("registerType can not be updated") + } if req.UserID != opUserID { return nil, errs.ErrNoPermission.WrapMsg("only admin can update other user info") } - if req.AreaCode != nil { - return nil, errs.ErrNoPermission.WrapMsg("areaCode can not be updated") - } - if req.PhoneNumber != nil { - return nil, errs.ErrNoPermission.WrapMsg("phoneNumber can not be updated") - } - if req.Account != nil { - return nil, errs.ErrNoPermission.WrapMsg("account can not be updated") - } - if req.Level != nil { - return nil, errs.ErrNoPermission.WrapMsg("level can not be updated") - } + case constant.AdminUser: default: return nil, errs.ErrNoPermission.WrapMsg("user type error") } - if err := o.checkUpdateInfo(ctx, req); err != nil { + + update, err := ToDBAttributeUpdate(req) + if err != nil { return nil, err } - update, err := ToDBAttributeUpdate(req) + credUpdate, credDel, err := ToDBCredentialUpdate(req, true) if err != nil { return nil, err } if len(update) > 0 { - if err := o.Database.UpdateUseInfo(ctx, req.UserID, update); err != nil { + if err := o.Database.UpdateUseInfo(ctx, req.UserID, update, credUpdate, credDel); err != nil { return nil, err } } @@ -185,7 +209,7 @@ func (o *chatSvr) AddUserAccount(ctx context.Context, req *chat.AddUserAccountRe return nil, err } - if err := o.checkTheUniqueness(ctx, req); err != nil { + if err := o.checkRegisterInfo(ctx, req.User, true); err != nil { return nil, err } @@ -205,6 +229,44 @@ func (o *chatSvr) AddUserAccount(ctx context.Context, req *chat.AddUserAccountRe if req.User.UserID == "" { return nil, errs.ErrInternalServer.WrapMsg("gen user id failed") } + } else { + _, err := o.Database.GetUser(ctx, req.User.UserID) + if err == nil { + return nil, errs.ErrArgs.WrapMsg("appoint user id already register") + } else if !dbutil.IsDBNotFound(err) { + return nil, err + } + } + + var ( + credentials []*chatdb.Credential + ) + + if req.User.PhoneNumber != "" { + credentials = append(credentials, &chatdb.Credential{ + UserID: req.User.UserID, + Account: BuildCredentialPhone(req.User.AreaCode, req.User.PhoneNumber), + Type: constant.CredentialPhone, + AllowChange: true, + }) + } + + if req.User.Account != "" { + credentials = append(credentials, &chatdb.Credential{ + UserID: req.User.UserID, + Account: req.User.Account, + Type: constant.CredentialAccount, + AllowChange: true, + }) + } + + if req.User.Email != "" { + credentials = append(credentials, &chatdb.Credential{ + UserID: req.User.UserID, + Account: req.User.Email, + Type: constant.CredentialEmail, + AllowChange: true, + }) } register := &chatdb.Register{ @@ -240,10 +302,9 @@ func (o *chatSvr) AddUserAccount(ctx context.Context, req *chat.AddUserAccountRe AllowAddFriend: constant.DefaultAllowAddFriend, } - if err := o.Database.RegisterUser(ctx, register, account, attribute); err != nil { + if err := o.Database.RegisterUser(ctx, register, account, attribute, credentials); err != nil { return nil, err } - return &chat.AddUserAccountResp{}, nil } @@ -339,52 +400,42 @@ func (o *chatSvr) SearchUserInfo(ctx context.Context, req *chat.SearchUserInfoRe }, nil } -func (o *chatSvr) checkTheUniqueness(ctx context.Context, req *chat.AddUserAccountReq) error { +func (o *chatSvr) CheckUserExist(ctx context.Context, req *chat.CheckUserExistReq) (resp *chat.CheckUserExistResp, err error) { + if req.User == nil { + return nil, errs.ErrArgs.WrapMsg("user is nil") + } if req.User.PhoneNumber != "" { - _, err := o.Database.TakeAttributeByPhone(ctx, req.User.AreaCode, req.User.PhoneNumber) - if err == nil { - return eerrs.ErrPhoneAlreadyRegister.Wrap() - } else if !dbutil.IsDBNotFound(err) { - return err + account, err := o.Database.TakeCredentialByAccount(ctx, BuildCredentialPhone(req.User.AreaCode, req.User.PhoneNumber)) + // err != nil is not found User + if err != nil && !errors.Is(err, mongo.ErrNoDocuments) { + return nil, err } - } else { - _, err := o.Database.TakeAttributeByEmail(ctx, req.User.Email) - if err == nil { - return eerrs.ErrEmailAlreadyRegister.Wrap() - } else if !dbutil.IsDBNotFound(err) { - return err + if account != nil { + log.ZDebug(ctx, "Check Number is ", account.Account) + log.ZDebug(ctx, "Check userID is ", account.UserID) + return &chat.CheckUserExistResp{Userid: account.UserID, IsRegistered: true}, nil } } - return nil -} - -func (o *chatSvr) CheckUserExist(ctx context.Context, req *chat.CheckUserExistReq) (resp *chat.CheckUserExistResp, err error) { - if req.User.PhoneNumber != "" { - attributeByPhone, err := o.Database.TakeAttributeByPhone(ctx, req.User.AreaCode, req.User.PhoneNumber) - // err != nil is not found User - if err != nil && errs.Unwrap(err) != mongo.ErrNoDocuments { + if req.User.Email != "" { + account, err := o.Database.TakeCredentialByAccount(ctx, req.User.AreaCode) + if err != nil && !errors.Is(err, mongo.ErrNoDocuments) { return nil, err } - if attributeByPhone != nil { - log.ZDebug(ctx, "Check Number is ", attributeByPhone.PhoneNumber) - log.ZDebug(ctx, "Check userID is ", attributeByPhone.UserID) - if attributeByPhone.PhoneNumber == req.User.PhoneNumber { - return &chat.CheckUserExistResp{Userid: attributeByPhone.UserID, IsRegistered: true}, nil - } + if account != nil { + log.ZDebug(ctx, "Check email is ", account.Account) + log.ZDebug(ctx, "Check userID is ", account.UserID) + return &chat.CheckUserExistResp{Userid: account.UserID, IsRegistered: true}, nil } - } else { - if req.User.Email != "" { - attributeByEmail, err := o.Database.TakeAttributeByEmail(ctx, req.User.Email) - if err != nil && errs.Unwrap(err) != mongo.ErrNoDocuments { - return nil, err - } - if attributeByEmail != nil { - log.ZDebug(ctx, "Check email is ", attributeByEmail.Email) - log.ZDebug(ctx, "Check userID is ", attributeByEmail.UserID) - if attributeByEmail.Email == req.User.Email { - return &chat.CheckUserExistResp{Userid: attributeByEmail.UserID, IsRegistered: true}, nil - } - } + } + if req.User.Account != "" { + account, err := o.Database.TakeCredentialByAccount(ctx, req.User.Account) + if err != nil && !errors.Is(err, mongo.ErrNoDocuments) { + return nil, err + } + if account != nil { + log.ZDebug(ctx, "Check account is ", account.Account) + log.ZDebug(ctx, "Check userID is ", account.UserID) + return &chat.CheckUserExistResp{Userid: account.UserID, IsRegistered: true}, nil } } return nil, nil diff --git a/internal/rpc/chat/utils.go b/internal/rpc/chat/utils.go index 03a95d0df..b8c1f1740 100644 --- a/internal/rpc/chat/utils.go +++ b/internal/rpc/chat/utils.go @@ -1,26 +1,20 @@ -// Copyright © 2023 OpenIM open source community. 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 chat import ( - "github.com/openimsdk/chat/pkg/common/db/table/chat" + "context" + "github.com/openimsdk/chat/pkg/common/db/dbutil" + table "github.com/openimsdk/chat/pkg/common/db/table/chat" + "github.com/openimsdk/chat/pkg/eerrs" + "github.com/openimsdk/chat/pkg/protocol/chat" "github.com/openimsdk/chat/pkg/protocol/common" + "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/utils/datautil" + "github.com/openimsdk/tools/utils/stringutil" + "strconv" + "strings" ) -func DbToPbAttribute(attribute *chat.Attribute) *common.UserPublicInfo { +func DbToPbAttribute(attribute *table.Attribute) *common.UserPublicInfo { if attribute == nil { return nil } @@ -35,11 +29,11 @@ func DbToPbAttribute(attribute *chat.Attribute) *common.UserPublicInfo { } } -func DbToPbAttributes(attributes []*chat.Attribute) []*common.UserPublicInfo { +func DbToPbAttributes(attributes []*table.Attribute) []*common.UserPublicInfo { return datautil.Slice(attributes, DbToPbAttribute) } -func DbToPbUserFullInfo(attribute *chat.Attribute) *common.UserFullInfo { +func DbToPbUserFullInfo(attribute *table.Attribute) *common.UserFullInfo { return &common.UserFullInfo{ UserID: attribute.UserID, Password: "", @@ -60,6 +54,59 @@ func DbToPbUserFullInfo(attribute *chat.Attribute) *common.UserFullInfo { } } -func DbToPbUserFullInfos(attributes []*chat.Attribute) []*common.UserFullInfo { +func DbToPbUserFullInfos(attributes []*table.Attribute) []*common.UserFullInfo { return datautil.Slice(attributes, DbToPbUserFullInfo) } + +func BuildCredentialPhone(areaCode, phone string) string { + return areaCode + " " + phone +} + +func (o *chatSvr) checkRegisterInfo(ctx context.Context, user *chat.RegisterUserInfo, isAdmin bool) error { + if user == nil { + return errs.ErrArgs.WrapMsg("user is nil") + } + if user.Email == "" && !(user.PhoneNumber != "" && user.AreaCode != "") && (!isAdmin || user.Account == "") { + return errs.ErrArgs.WrapMsg("at least one valid account is required") + } + if user.PhoneNumber != "" { + if !strings.HasPrefix(user.AreaCode, "+") { + user.AreaCode = "+" + user.AreaCode + } + if _, err := strconv.ParseUint(user.AreaCode[1:], 10, 64); err != nil { + return errs.ErrArgs.WrapMsg("area code must be number") + } + if _, err := strconv.ParseUint(user.PhoneNumber, 10, 64); err != nil { + return errs.ErrArgs.WrapMsg("phone number must be number") + } + _, err := o.Database.TakeAttributeByPhone(ctx, user.AreaCode, user.PhoneNumber) + if err == nil { + return eerrs.ErrPhoneAlreadyRegister.Wrap() + } else if !dbutil.IsDBNotFound(err) { + return err + } + } + if user.Account != "" { + if !stringutil.IsAlphanumeric(user.Account) { + return errs.ErrArgs.WrapMsg("account must be alphanumeric") + } + _, err := o.Database.TakeAttributeByAccount(ctx, user.Account) + if err == nil { + return eerrs.ErrAccountAlreadyRegister.Wrap() + } else if !dbutil.IsDBNotFound(err) { + return err + } + } + if user.Email != "" { + if !stringutil.IsValidEmail(user.Email) { + return errs.ErrArgs.WrapMsg("invalid email") + } + _, err := o.Database.TakeAttributeByAccount(ctx, user.Email) + if err == nil { + return eerrs.ErrAccountAlreadyRegister.Wrap() + } else if !dbutil.IsDBNotFound(err) { + return err + } + } + return nil +} diff --git a/pkg/common/config/config.go b/pkg/common/config/config.go index 76acd6c65..2348e9f0e 100644 --- a/pkg/common/config/config.go +++ b/pkg/common/config/config.go @@ -145,6 +145,7 @@ type Chat struct { Key string `mapstructure:"key"` Secret string `mapstructure:"secret"` } `mapstructure:"liveKit"` + AllowRegister bool `mapstructure:"allowRegister"` } type Admin struct { diff --git a/pkg/common/constant/constant.go b/pkg/common/constant/constant.go index ed2e77854..0c0acec5d 100644 --- a/pkg/common/constant/constant.go +++ b/pkg/common/constant/constant.go @@ -1,17 +1,3 @@ -// Copyright © 2023 OpenIM open source community. 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 constant import "github.com/openimsdk/protocol/constant" @@ -108,6 +94,20 @@ const ( const CtxApiToken = "api-token" const ( - EmailRegister = 1 - PhoneRegister = 2 + AccountRegister = iota + EmailRegister + PhoneRegister +) + +const ( + GenderFemale = 0 // female + GenderMale = 1 // male + GenderUnknown = 2 // unknown +) + +// Credential Type +const ( + CredentialAccount = iota + CredentialPhone + CredentialEmail ) diff --git a/pkg/common/db/database/chat.go b/pkg/common/db/database/chat.go index e618845a4..55acd558a 100644 --- a/pkg/common/db/database/chat.go +++ b/pkg/common/db/database/chat.go @@ -31,26 +31,24 @@ import ( type ChatDatabaseInterface interface { GetUser(ctx context.Context, userID string) (account *chatdb.Account, err error) - UpdateUseInfo(ctx context.Context, userID string, attribute map[string]any) (err error) + UpdateUseInfo(ctx context.Context, userID string, attribute map[string]any, updateCred, delCred []*chatdb.Credential) (err error) FindAttribute(ctx context.Context, userIDs []string) ([]*chatdb.Attribute, error) FindAttributeByAccount(ctx context.Context, accounts []string) ([]*chatdb.Attribute, error) TakeAttributeByPhone(ctx context.Context, areaCode string, phoneNumber string) (*chatdb.Attribute, error) TakeAttributeByEmail(ctx context.Context, Email string) (*chatdb.Attribute, error) TakeAttributeByAccount(ctx context.Context, account string) (*chatdb.Attribute, error) TakeAttributeByUserID(ctx context.Context, userID string) (*chatdb.Attribute, error) + TakeAccount(ctx context.Context, userID string) (*chatdb.Account, error) + TakeCredentialByAccount(ctx context.Context, account string) (*chatdb.Credential, error) + TakeCredentialsByUserID(ctx context.Context, userID string) ([]*chatdb.Credential, error) + TakeLastVerifyCode(ctx context.Context, account string) (*chatdb.VerifyCode, error) Search(ctx context.Context, normalUser int32, keyword string, gender int32, pagination pagination.Pagination) (int64, []*chatdb.Attribute, error) SearchUser(ctx context.Context, keyword string, userIDs []string, genders []int32, pagination pagination.Pagination) (int64, []*chatdb.Attribute, error) CountVerifyCodeRange(ctx context.Context, account string, start time.Time, end time.Time) (int64, error) AddVerifyCode(ctx context.Context, verifyCode *chatdb.VerifyCode, fn func() error) error UpdateVerifyCodeIncrCount(ctx context.Context, id string) error - TakeLastVerifyCode(ctx context.Context, account string) (*chatdb.VerifyCode, error) DelVerifyCode(ctx context.Context, id string) error - RegisterUser(ctx context.Context, register *chatdb.Register, account *chatdb.Account, attribute *chatdb.Attribute) error - GetAccount(ctx context.Context, userID string) (*chatdb.Account, error) - GetAttribute(ctx context.Context, userID string) (*chatdb.Attribute, error) - GetAttributeByAccount(ctx context.Context, account string) (*chatdb.Attribute, error) - GetAttributeByPhone(ctx context.Context, areaCode string, phoneNumber string) (*chatdb.Attribute, error) - GetAttributeByEmail(ctx context.Context, email string) (*chatdb.Attribute, error) + RegisterUser(ctx context.Context, register *chatdb.Register, account *chatdb.Account, attribute *chatdb.Attribute, credentials []*chatdb.Credential) error LoginRecord(ctx context.Context, record *chatdb.UserLoginRecord, verifyCodeID *string) error UpdatePassword(ctx context.Context, userID string, password string) error UpdatePasswordAndDeleteVerifyCode(ctx context.Context, userID string, password string, codeID string) error @@ -73,6 +71,10 @@ func NewChatDatabase(cli *mongoutil.Client) (ChatDatabaseInterface, error) { if err != nil { return nil, err } + credential, err := chat.NewCredential(cli.GetDB()) + if err != nil { + return nil, err + } userLoginRecord, err := chat.NewUserLoginRecord(cli.GetDB()) if err != nil { return nil, err @@ -90,6 +92,7 @@ func NewChatDatabase(cli *mongoutil.Client) (ChatDatabaseInterface, error) { register: register, account: account, attribute: attribute, + credential: credential, userLoginRecord: userLoginRecord, verifyCode: verifyCode, forbiddenAccount: forbiddenAccount, @@ -101,6 +104,7 @@ type ChatDatabase struct { register chatdb.RegisterInterface account chatdb.AccountInterface attribute chatdb.AttributeInterface + credential chatdb.CredentialInterface userLoginRecord chatdb.UserLoginRecordInterface verifyCode chatdb.VerifyCodeInterface forbiddenAccount admin.ForbiddenAccountInterface @@ -110,8 +114,21 @@ func (o *ChatDatabase) GetUser(ctx context.Context, userID string) (account *cha return o.account.Take(ctx, userID) } -func (o *ChatDatabase) UpdateUseInfo(ctx context.Context, userID string, attribute map[string]any) (err error) { - return o.attribute.Update(ctx, userID, attribute) +func (o *ChatDatabase) UpdateUseInfo(ctx context.Context, userID string, attribute map[string]any, updateCred, delCred []*chatdb.Credential) (err error) { + return o.tx.Transaction(ctx, func(ctx context.Context) error { + if err = o.attribute.Update(ctx, userID, attribute); err != nil { + return err + } + for _, credential := range updateCred { + if err = o.credential.CreateOrUpdateAccount(ctx, credential); err != nil { + return err + } + } + if err = o.credential.DeleteByUserIDType(ctx, delCred...); err != nil { + return err + } + return nil + }) } func (o *ChatDatabase) FindAttribute(ctx context.Context, userIDs []string) ([]*chatdb.Attribute, error) { @@ -138,6 +155,22 @@ func (o *ChatDatabase) TakeAttributeByUserID(ctx context.Context, userID string) return o.attribute.Take(ctx, userID) } +func (o *ChatDatabase) TakeLastVerifyCode(ctx context.Context, account string) (*chatdb.VerifyCode, error) { + return o.verifyCode.TakeLast(ctx, account) +} + +func (o *ChatDatabase) TakeAccount(ctx context.Context, userID string) (*chatdb.Account, error) { + return o.account.Take(ctx, userID) +} + +func (o *ChatDatabase) TakeCredentialByAccount(ctx context.Context, account string) (*chatdb.Credential, error) { + return o.credential.TakeAccount(ctx, account) +} + +func (o *ChatDatabase) TakeCredentialsByUserID(ctx context.Context, userID string) ([]*chatdb.Credential, error) { + return o.credential.Find(ctx, userID) +} + func (o *ChatDatabase) Search(ctx context.Context, normalUser int32, keyword string, genders int32, pagination pagination.Pagination) (total int64, attributes []*chatdb.Attribute, err error) { var forbiddenIDs []string if int(normalUser) == constant.NormalUser { @@ -177,15 +210,11 @@ func (o *ChatDatabase) UpdateVerifyCodeIncrCount(ctx context.Context, id string) return o.verifyCode.Incr(ctx, id) } -func (o *ChatDatabase) TakeLastVerifyCode(ctx context.Context, account string) (*chatdb.VerifyCode, error) { - return o.verifyCode.TakeLast(ctx, account) -} - func (o *ChatDatabase) DelVerifyCode(ctx context.Context, id string) error { return o.verifyCode.Delete(ctx, id) } -func (o *ChatDatabase) RegisterUser(ctx context.Context, register *chatdb.Register, account *chatdb.Account, attribute *chatdb.Attribute) error { +func (o *ChatDatabase) RegisterUser(ctx context.Context, register *chatdb.Register, account *chatdb.Account, attribute *chatdb.Attribute, credentials []*chatdb.Credential) error { return o.tx.Transaction(ctx, func(ctx context.Context) error { if err := o.register.Create(ctx, register); err != nil { return err @@ -196,30 +225,13 @@ func (o *ChatDatabase) RegisterUser(ctx context.Context, register *chatdb.Regist if err := o.attribute.Create(ctx, attribute); err != nil { return err } + if err := o.credential.Create(ctx, credentials...); err != nil { + return err + } return nil }) } -func (o *ChatDatabase) GetAccount(ctx context.Context, userID string) (*chatdb.Account, error) { - return o.account.Take(ctx, userID) -} - -func (o *ChatDatabase) GetAttribute(ctx context.Context, userID string) (*chatdb.Attribute, error) { - return o.attribute.Take(ctx, userID) -} - -func (o *ChatDatabase) GetAttributeByAccount(ctx context.Context, account string) (*chatdb.Attribute, error) { - return o.attribute.TakeAccount(ctx, account) -} - -func (o *ChatDatabase) GetAttributeByPhone(ctx context.Context, areaCode string, phoneNumber string) (*chatdb.Attribute, error) { - return o.attribute.TakePhone(ctx, areaCode, phoneNumber) -} - -func (o *ChatDatabase) GetAttributeByEmail(ctx context.Context, email string) (*chatdb.Attribute, error) { - return o.attribute.TakeEmail(ctx, email) -} - func (o *ChatDatabase) LoginRecord(ctx context.Context, record *chatdb.UserLoginRecord, verifyCodeID *string) error { return o.tx.Transaction(ctx, func(ctx context.Context) error { if err := o.userLoginRecord.Create(ctx, record); err != nil { diff --git a/pkg/common/db/model/chat/credential.go b/pkg/common/db/model/chat/credential.go new file mode 100644 index 000000000..7564c45ef --- /dev/null +++ b/pkg/common/db/model/chat/credential.go @@ -0,0 +1,142 @@ +package chat + +import ( + "context" + "go.mongodb.org/mongo-driver/mongo/options" + + "github.com/openimsdk/chat/pkg/common/db/table/chat" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + "github.com/openimsdk/tools/errs" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" +) + +func NewCredential(db *mongo.Database) (chat.CredentialInterface, error) { + coll := db.Collection("credential") + _, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{ + { + Keys: bson.D{ + {Key: "user_id", Value: 1}, + {Key: "type", Value: 1}, + }, + Options: options.Index().SetUnique(true), + }, + { + Keys: bson.D{ + {Key: "account", Value: 1}, + }, + Options: options.Index().SetUnique(true), + }, + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &Credential{coll: coll}, nil +} + +type Credential struct { + coll *mongo.Collection +} + +func (o *Credential) Create(ctx context.Context, credential ...*chat.Credential) error { + return mongoutil.InsertMany(ctx, o.coll, credential) +} + +func (o *Credential) CreateOrUpdateAccount(ctx context.Context, credential *chat.Credential) error { + return mongoutil.UpdateOne(ctx, o.coll, bson.M{ + "user_id": credential.UserID, + "type": credential.Type, + }, bson.M{ + "$set": bson.M{ + "account": credential.Account, + }, + "$setOnInsert": bson.M{ + "user_id": credential.UserID, + "type": credential.Type, + "allow_change": credential.AllowChange, + }, + }, false, options.Update().SetUpsert(true)) +} + +func (o *Credential) Update(ctx context.Context, userID string, data map[string]any) error { + if len(data) == 0 { + return nil + } + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"user_id": userID}, bson.M{"$set": data}, false) +} + +func (o *Credential) Find(ctx context.Context, userID string) ([]*chat.Credential, error) { + return mongoutil.Find[*chat.Credential](ctx, o.coll, bson.M{"user_id": userID}) +} + +func (o *Credential) FindAccount(ctx context.Context, accounts []string) ([]*chat.Credential, error) { + return mongoutil.Find[*chat.Credential](ctx, o.coll, bson.M{"account": bson.M{"$in": accounts}}) +} + +func (o *Credential) Search(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*chat.Credential, error) { + return o.SearchUser(ctx, keyword, nil, pagination) +} + +func (o *Credential) TakeAccount(ctx context.Context, account string) (*chat.Credential, error) { + return mongoutil.FindOne[*chat.Credential](ctx, o.coll, bson.M{"account": account}) +} + +func (o *Credential) Take(ctx context.Context, userID string) (*chat.Credential, error) { + return mongoutil.FindOne[*chat.Credential](ctx, o.coll, bson.M{"user_id": userID}) +} + +func (o *Credential) SearchNormalUser(ctx context.Context, keyword string, forbiddenIDs []string, pagination pagination.Pagination) (int64, []*chat.Credential, error) { + filter := bson.M{} + + if len(forbiddenIDs) > 0 { + filter["user_id"] = bson.M{ + "$nin": forbiddenIDs, + } + } + if keyword != "" { + filter["$or"] = []bson.M{ + {"user_id": bson.M{"$regex": keyword, "$options": "i"}}, + {"account": bson.M{"$regex": keyword, "$options": "i"}}, + } + } + return mongoutil.FindPage[*chat.Credential](ctx, o.coll, filter, pagination) +} + +func (o *Credential) SearchUser(ctx context.Context, keyword string, userIDs []string, pagination pagination.Pagination) (int64, []*chat.Credential, error) { + filter := bson.M{} + + if len(userIDs) > 0 { + filter["user_id"] = bson.M{ + "$in": userIDs, + } + } + if keyword != "" { + filter["$or"] = []bson.M{ + {"user_id": bson.M{"$regex": keyword, "$options": "i"}}, + {"account": bson.M{"$regex": keyword, "$options": "i"}}, + } + } + return mongoutil.FindPage[*chat.Credential](ctx, o.coll, filter, pagination) +} + +func (o *Credential) Delete(ctx context.Context, userIDs []string) error { + if len(userIDs) == 0 { + return nil + } + return mongoutil.DeleteMany(ctx, o.coll, bson.M{"user_id": bson.M{"$in": userIDs}}) +} + +func (o *Credential) DeleteByUserIDType(ctx context.Context, credentials ...*chat.Credential) error { + var filters []bson.M + for _, credential := range credentials { + filters = append(filters, bson.M{ + "user_id": credential.UserID, + "type": credential.Type, + }) + } + + query := bson.M{"$or": filters} + + return mongoutil.DeleteMany(ctx, o.coll, query) +} diff --git a/pkg/common/db/table/chat/attribute.go b/pkg/common/db/table/chat/attribute.go index d77f06176..4e033ba16 100644 --- a/pkg/common/db/table/chat/attribute.go +++ b/pkg/common/db/table/chat/attribute.go @@ -1,17 +1,3 @@ -// Copyright © 2023 OpenIM open source community. 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 chat import ( diff --git a/pkg/common/db/table/chat/credential.go b/pkg/common/db/table/chat/credential.go new file mode 100644 index 000000000..e4d23d6c8 --- /dev/null +++ b/pkg/common/db/table/chat/credential.go @@ -0,0 +1,32 @@ +package chat + +import ( + "context" + "github.com/openimsdk/tools/db/pagination" +) + +type Credential struct { + UserID string `bson:"user_id"` + Account string `bson:"account"` + Type int `bson:"type"` // 1:phone;2:email + AllowChange bool `bson:"allow_change"` +} + +func (Credential) TableName() string { + return "credentials" +} + +type CredentialInterface interface { + Create(ctx context.Context, credential ...*Credential) error + CreateOrUpdateAccount(ctx context.Context, credential *Credential) error + Update(ctx context.Context, userID string, data map[string]any) error + Find(ctx context.Context, userID string) ([]*Credential, error) + FindAccount(ctx context.Context, accounts []string) ([]*Credential, error) + Search(ctx context.Context, keyword string, pagination pagination.Pagination) (int64, []*Credential, error) + TakeAccount(ctx context.Context, account string) (*Credential, error) + Take(ctx context.Context, userID string) (*Credential, error) + SearchNormalUser(ctx context.Context, keyword string, forbiddenID []string, pagination pagination.Pagination) (int64, []*Credential, error) + SearchUser(ctx context.Context, keyword string, userIDs []string, pagination pagination.Pagination) (int64, []*Credential, error) + Delete(ctx context.Context, userIDs []string) error + DeleteByUserIDType(ctx context.Context, credentials ...*Credential) error +} diff --git a/pkg/common/imapi/caller.go b/pkg/common/imapi/caller.go index 0a3923cb2..24b9d545d 100644 --- a/pkg/common/imapi/caller.go +++ b/pkg/common/imapi/caller.go @@ -1,17 +1,3 @@ -// Copyright © 2023 OpenIM open source community. 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 imapi import ( diff --git a/pkg/email/mail_test.go b/pkg/email/mail_test.go index c6824510a..0f9ebe348 100644 --- a/pkg/email/mail_test.go +++ b/pkg/email/mail_test.go @@ -1,77 +1,51 @@ -// Copyright © 2023 OpenIM open source community. 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 email -import ( - "context" - "errors" - "fmt" - "io/ioutil" - "os" - "testing" - - "github.com/openimsdk/chat/pkg/common/config" - "gopkg.in/yaml.v3" -) - -func TestEmail(T *testing.T) { - if err := InitConfig(); err != nil { - fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) - os.Exit(-1) - } - tests := []struct { - name string - ctx context.Context - mail string - code string - want error - }{ - { - name: "success send email", - ctx: context.Background(), - mail: "test@gmail.com", - code: "5555", - want: errors.New("nil"), - }, - { - name: "fail send email", - ctx: context.Background(), - mail: "", - code: "5555", - want: errors.New("dial tcp :0: connectex: The requested address is not valid in its context."), - }, - } - mail := NewMail() - - for _, tt := range tests { - T.Run(tt.name, func(t *testing.T) { - if got := mail.SendMail(tt.ctx, tt.mail, tt.code); errors.Is(got, tt.want) { - t.Errorf("%v have a err,%v", tt.name, tt.want) - } - }) - } -} - -func InitConfig() error { - yam, err := ioutil.ReadFile("../../config/config.yaml") - if err != nil { - return err - } - err = yaml.Unmarshal(yam, &config.Config) - if err != nil { - return err - } - return nil -} +//func TestEmail(T *testing.T) { +// if err := InitConfig(); err != nil { +// fmt.Fprintf(os.Stderr, "\n\nexit -1: \n%+v\n\n", err) +// os.Exit(-1) +// } +// tests := []struct { +// name string +// ctx context.Context +// mail string +// code string +// want error +// }{ +// { +// name: "success send email", +// ctx: context.Background(), +// mail: "test@gmail.com", +// code: "5555", +// want: errors.New("nil"), +// }, +// { +// name: "fail send email", +// ctx: context.Background(), +// mail: "", +// code: "5555", +// want: errors.New("dial tcp :0: connectex: The requested address is not valid in its context."), +// }, +// } +// mail := NewMail() +// +// for _, tt := range tests { +// T.Run(tt.name, func(t *testing.T) { +// if got := mail.SendMail(tt.ctx, tt.mail, tt.code); errors.Is(got, tt.want) { +// t.Errorf("%v have a err,%v", tt.name, tt.want) +// } +// }) +// } +//} +// +//func InitConfig() error { +// yam, err := ioutil.ReadFile("../../config/config.yaml") +// if err != nil { +// return err +// } +// err = yaml.Unmarshal(yam, &config.Config) +// if err != nil { +// return err +// } +// return nil +//} diff --git a/pkg/protocol/chat/chat.pb.go b/pkg/protocol/chat/chat.pb.go index 992e9b2e5..b5a68d7ca 100644 --- a/pkg/protocol/chat/chat.pb.go +++ b/pkg/protocol/chat/chat.pb.go @@ -15,7 +15,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.33.0 -// protoc v5.27.1 +// protoc v5.26.0 // source: chat/chat.proto package chat @@ -2767,6 +2767,176 @@ func (*DelUserAccountResp) Descriptor() ([]byte, []int) { return file_chat_chat_proto_rawDescGZIP(), []int{42} } +type SetAllowRegisterReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AllowRegister bool `protobuf:"varint,1,opt,name=allowRegister,proto3" json:"allowRegister"` +} + +func (x *SetAllowRegisterReq) Reset() { + *x = SetAllowRegisterReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[43] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SetAllowRegisterReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetAllowRegisterReq) ProtoMessage() {} + +func (x *SetAllowRegisterReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[43] + 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 SetAllowRegisterReq.ProtoReflect.Descriptor instead. +func (*SetAllowRegisterReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{43} +} + +func (x *SetAllowRegisterReq) GetAllowRegister() bool { + if x != nil { + return x.AllowRegister + } + return false +} + +type SetAllowRegisterResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *SetAllowRegisterResp) Reset() { + *x = SetAllowRegisterResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[44] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SetAllowRegisterResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetAllowRegisterResp) ProtoMessage() {} + +func (x *SetAllowRegisterResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[44] + 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 SetAllowRegisterResp.ProtoReflect.Descriptor instead. +func (*SetAllowRegisterResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{44} +} + +type GetAllowRegisterReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetAllowRegisterReq) Reset() { + *x = GetAllowRegisterReq{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[45] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetAllowRegisterReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetAllowRegisterReq) ProtoMessage() {} + +func (x *GetAllowRegisterReq) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[45] + 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 GetAllowRegisterReq.ProtoReflect.Descriptor instead. +func (*GetAllowRegisterReq) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{45} +} + +type GetAllowRegisterResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AllowRegister bool `protobuf:"varint,1,opt,name=allowRegister,proto3" json:"allowRegister"` +} + +func (x *GetAllowRegisterResp) Reset() { + *x = GetAllowRegisterResp{} + if protoimpl.UnsafeEnabled { + mi := &file_chat_chat_proto_msgTypes[46] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetAllowRegisterResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetAllowRegisterResp) ProtoMessage() {} + +func (x *GetAllowRegisterResp) ProtoReflect() protoreflect.Message { + mi := &file_chat_chat_proto_msgTypes[46] + 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 GetAllowRegisterResp.ProtoReflect.Descriptor instead. +func (*GetAllowRegisterResp) Descriptor() ([]byte, []int) { + return file_chat_chat_proto_rawDescGZIP(), []int{46} +} + +func (x *GetAllowRegisterResp) GetAllowRegister() bool { + if x != nil { + return x.AllowRegister + } + return false +} + var File_chat_chat_proto protoreflect.FileDescriptor var file_chat_chat_proto_rawDesc = []byte{ @@ -3136,117 +3306,138 @@ var file_chat_chat_proto_rawDesc = []byte{ 0x6e, 0x74, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x22, 0x14, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x32, 0xa3, 0x0d, 0x0a, 0x04, 0x63, 0x68, 0x61, 0x74, 0x12, 0x51, - 0x0a, 0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, - 0x12, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, - 0x1a, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, - 0x70, 0x12, 0x51, 0x0a, 0x0e, 0x41, 0x64, 0x64, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, - 0x74, 0x2e, 0x41, 0x64, 0x64, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, - 0x74, 0x2e, 0x41, 0x64, 0x64, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x52, 0x65, 0x73, 0x70, 0x12, 0x63, 0x0a, 0x14, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, - 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x24, 0x2e, 0x6f, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x22, 0x3b, 0x0a, 0x13, 0x53, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, + 0x77, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x24, 0x0a, 0x0d, + 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x22, 0x16, 0x0a, 0x14, 0x53, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x52, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x22, 0x15, 0x0a, 0x13, 0x47, 0x65, + 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, + 0x71, 0x22, 0x3c, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x6c, 0x6c, + 0x6f, 0x77, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x32, + 0xd5, 0x0e, 0x0a, 0x04, 0x63, 0x68, 0x61, 0x74, 0x12, 0x51, 0x0a, 0x0e, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1e, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, + 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, + 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x51, 0x0a, 0x0e, 0x41, + 0x64, 0x64, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1e, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x41, 0x64, 0x64, 0x55, + 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x41, 0x64, 0x64, 0x55, + 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x63, + 0x0a, 0x14, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x50, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x52, - 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, - 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, - 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5d, 0x0a, 0x12, 0x46, 0x69, 0x6e, - 0x64, 0x55, 0x73, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x12, - 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x46, 0x69, - 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x6e, 0x66, 0x6f, - 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, - 0x74, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5d, 0x0a, 0x12, 0x53, 0x65, 0x61, 0x72, - 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x46, 0x75, 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x22, - 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x61, - 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x46, 0x75, 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, - 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, - 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x46, 0x75, 0x6c, 0x6c, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x57, 0x0a, 0x10, 0x46, 0x69, 0x6e, 0x64, 0x55, - 0x73, 0x65, 0x72, 0x46, 0x75, 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20, 0x2e, 0x6f, 0x70, - 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, - 0x65, 0x72, 0x46, 0x75, 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, + 0x65, 0x73, 0x70, 0x12, 0x5d, 0x0a, 0x12, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x50, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, + 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x46, 0x69, 0x6e, 0x64, - 0x55, 0x73, 0x65, 0x72, 0x46, 0x75, 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, - 0x12, 0x51, 0x0a, 0x0e, 0x53, 0x65, 0x6e, 0x64, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, - 0x64, 0x65, 0x12, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, - 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x52, - 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, - 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x12, 0x45, 0x0a, 0x0a, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x64, - 0x65, 0x12, 0x1a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, - 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, - 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x56, 0x65, 0x72, 0x69, - 0x66, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4b, 0x0a, 0x0c, 0x52, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x6f, 0x70, 0x65, - 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, - 0x72, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, - 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x55, - 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x36, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, - 0x12, 0x15, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x4c, - 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, - 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, - 0x4e, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, - 0x12, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x52, - 0x65, 0x73, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x1a, - 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x52, 0x65, - 0x73, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, - 0x51, 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, - 0x64, 0x12, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, + 0x55, 0x73, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x5d, 0x0a, 0x12, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, + 0x46, 0x75, 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, + 0x72, 0x46, 0x75, 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x55, 0x73, 0x65, 0x72, 0x46, 0x75, 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, + 0x70, 0x12, 0x57, 0x0a, 0x10, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x46, 0x75, 0x6c, + 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, + 0x68, 0x61, 0x74, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x46, 0x75, 0x6c, 0x6c, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x46, 0x75, + 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x51, 0x0a, 0x0e, 0x53, 0x65, + 0x6e, 0x64, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1e, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x56, + 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x56, + 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x45, 0x0a, + 0x0a, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, + 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x64, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x4b, 0x0a, 0x0c, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x55, 0x73, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, + 0x61, 0x74, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x52, + 0x65, 0x71, 0x1a, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, + 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, + 0x70, 0x12, 0x36, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x15, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, + 0x71, 0x1a, 0x16, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, + 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4e, 0x0a, 0x0d, 0x52, 0x65, 0x73, + 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x1d, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x52, 0x65, 0x73, 0x65, 0x74, 0x50, 0x61, + 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x52, 0x65, 0x73, 0x65, 0x74, 0x50, 0x61, 0x73, + 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x51, 0x0a, 0x0e, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x1e, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x51, 0x0a, 0x0e, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x45, 0x78, 0x69, 0x73, 0x74, 0x12, 0x1e, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x43, 0x68, 0x65, + 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x45, 0x78, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1f, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x43, 0x68, 0x65, + 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x45, 0x78, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x51, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x12, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, + 0x44, 0x65, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, - 0x73, 0x70, 0x12, 0x51, 0x0a, 0x0e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x45, - 0x78, 0x69, 0x73, 0x74, 0x12, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, - 0x61, 0x74, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x45, 0x78, 0x69, 0x73, - 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, - 0x61, 0x74, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x45, 0x78, 0x69, 0x73, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x51, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x55, 0x73, 0x65, 0x72, - 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, - 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x44, 0x65, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, - 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x44, 0x65, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, + 0x44, 0x65, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x54, 0x0a, 0x0f, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, + 0x68, 0x61, 0x74, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x63, 0x68, 0x61, 0x74, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x54, 0x0a, 0x0f, 0x46, 0x69, 0x6e, 0x64, - 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x2e, 0x6f, 0x70, - 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, - 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x6f, - 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, - 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x54, - 0x0a, 0x0f, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x55, 0x73, 0x65, - 0x72, 0x12, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, - 0x46, 0x69, 0x6e, 0x64, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, - 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, - 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x55, 0x73, 0x65, 0x72, - 0x52, 0x65, 0x73, 0x70, 0x12, 0x51, 0x0a, 0x0e, 0x4f, 0x70, 0x65, 0x6e, 0x49, 0x4d, 0x43, 0x61, - 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, - 0x63, 0x68, 0x61, 0x74, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x49, 0x4d, 0x43, 0x61, 0x6c, 0x6c, 0x62, - 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, - 0x63, 0x68, 0x61, 0x74, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x49, 0x4d, 0x43, 0x61, 0x6c, 0x6c, 0x62, - 0x61, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x12, 0x51, 0x0a, 0x0e, 0x55, 0x73, 0x65, 0x72, 0x4c, - 0x6f, 0x67, 0x69, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, - 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, - 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, - 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, - 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x51, 0x0a, 0x0e, 0x53, 0x65, - 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1e, 0x2e, 0x6f, - 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, - 0x68, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x6f, - 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, - 0x68, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x6c, 0x0a, - 0x17, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x46, 0x6f, 0x72, 0x56, 0x69, 0x64, 0x65, - 0x6f, 0x4d, 0x65, 0x65, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, - 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x46, - 0x6f, 0x72, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x4d, 0x65, 0x65, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, - 0x71, 0x1a, 0x28, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, - 0x47, 0x65, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x46, 0x6f, 0x72, 0x56, 0x69, 0x64, 0x65, 0x6f, - 0x4d, 0x65, 0x65, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x42, 0x2d, 0x5a, 0x2b, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, - 0x73, 0x64, 0x6b, 0x2f, 0x63, 0x68, 0x61, 0x74, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x63, 0x68, 0x61, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1f, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x41, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x51, + 0x0a, 0x0e, 0x4f, 0x70, 0x65, 0x6e, 0x49, 0x4d, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, + 0x12, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x4f, + 0x70, 0x65, 0x6e, 0x49, 0x4d, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, + 0x1a, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x4f, + 0x70, 0x65, 0x6e, 0x49, 0x4d, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x73, + 0x70, 0x12, 0x51, 0x0a, 0x0e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, + 0x74, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, + 0x74, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x51, 0x0a, 0x0e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, + 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x6c, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x46, 0x6f, 0x72, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x4d, 0x65, 0x65, 0x74, 0x69, + 0x6e, 0x67, 0x12, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, + 0x2e, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x46, 0x6f, 0x72, 0x56, 0x69, 0x64, 0x65, + 0x6f, 0x4d, 0x65, 0x65, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x28, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x46, 0x6f, 0x72, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x4d, 0x65, 0x65, 0x74, 0x69, 0x6e, + 0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x57, 0x0a, 0x10, 0x53, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, + 0x77, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x53, 0x65, 0x74, 0x41, 0x6c, 0x6c, + 0x6f, 0x77, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x57, + 0x0a, 0x10, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, + 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, + 0x61, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x42, 0x2d, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x73, 0x64, 0x6b, 0x2f, + 0x63, 0x68, 0x61, 0x74, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, + 0x6c, 0x2f, 0x63, 0x68, 0x61, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -3261,7 +3452,7 @@ func file_chat_chat_proto_rawDescGZIP() []byte { return file_chat_chat_proto_rawDescData } -var file_chat_chat_proto_msgTypes = make([]protoimpl.MessageInfo, 46) +var file_chat_chat_proto_msgTypes = make([]protoimpl.MessageInfo, 50) var file_chat_chat_proto_goTypes = []interface{}{ (*UserIdentity)(nil), // 0: openim.chat.UserIdentity (*UpdateUserInfoReq)(nil), // 1: openim.chat.UpdateUserInfoReq @@ -3306,45 +3497,49 @@ var file_chat_chat_proto_goTypes = []interface{}{ (*CheckUserExistResp)(nil), // 40: openim.chat.CheckUserExistResp (*DelUserAccountReq)(nil), // 41: openim.chat.DelUserAccountReq (*DelUserAccountResp)(nil), // 42: openim.chat.DelUserAccountResp - nil, // 43: openim.chat.FindUserAccountResp.UserAccountMapEntry - nil, // 44: openim.chat.FindAccountUserResp.AccountUserMapEntry - nil, // 45: openim.chat.UserLoginCountResp.CountEntry - (*wrapperspb.StringValue)(nil), // 46: openim.protobuf.StringValue - (*wrapperspb.Int32Value)(nil), // 47: openim.protobuf.Int32Value - (*wrapperspb.Int64Value)(nil), // 48: openim.protobuf.Int64Value - (*common.UserPublicInfo)(nil), // 49: openim.chat.common.UserPublicInfo - (*sdkws.RequestPagination)(nil), // 50: openim.sdkws.RequestPagination - (*common.UserFullInfo)(nil), // 51: openim.chat.common.UserFullInfo + (*SetAllowRegisterReq)(nil), // 43: openim.chat.SetAllowRegisterReq + (*SetAllowRegisterResp)(nil), // 44: openim.chat.SetAllowRegisterResp + (*GetAllowRegisterReq)(nil), // 45: openim.chat.GetAllowRegisterReq + (*GetAllowRegisterResp)(nil), // 46: openim.chat.GetAllowRegisterResp + nil, // 47: openim.chat.FindUserAccountResp.UserAccountMapEntry + nil, // 48: openim.chat.FindAccountUserResp.AccountUserMapEntry + nil, // 49: openim.chat.UserLoginCountResp.CountEntry + (*wrapperspb.StringValue)(nil), // 50: openim.protobuf.StringValue + (*wrapperspb.Int32Value)(nil), // 51: openim.protobuf.Int32Value + (*wrapperspb.Int64Value)(nil), // 52: openim.protobuf.Int64Value + (*common.UserPublicInfo)(nil), // 53: openim.chat.common.UserPublicInfo + (*sdkws.RequestPagination)(nil), // 54: openim.sdkws.RequestPagination + (*common.UserFullInfo)(nil), // 55: openim.chat.common.UserFullInfo } var file_chat_chat_proto_depIdxs = []int32{ - 46, // 0: openim.chat.UpdateUserInfoReq.account:type_name -> openim.protobuf.StringValue - 46, // 1: openim.chat.UpdateUserInfoReq.phoneNumber:type_name -> openim.protobuf.StringValue - 46, // 2: openim.chat.UpdateUserInfoReq.areaCode:type_name -> openim.protobuf.StringValue - 46, // 3: openim.chat.UpdateUserInfoReq.email:type_name -> openim.protobuf.StringValue - 46, // 4: openim.chat.UpdateUserInfoReq.nickname:type_name -> openim.protobuf.StringValue - 46, // 5: openim.chat.UpdateUserInfoReq.faceURL:type_name -> openim.protobuf.StringValue - 47, // 6: openim.chat.UpdateUserInfoReq.gender:type_name -> openim.protobuf.Int32Value - 47, // 7: openim.chat.UpdateUserInfoReq.level:type_name -> openim.protobuf.Int32Value - 48, // 8: openim.chat.UpdateUserInfoReq.birth:type_name -> openim.protobuf.Int64Value - 47, // 9: openim.chat.UpdateUserInfoReq.allowAddFriend:type_name -> openim.protobuf.Int32Value - 47, // 10: openim.chat.UpdateUserInfoReq.allowBeep:type_name -> openim.protobuf.Int32Value - 47, // 11: openim.chat.UpdateUserInfoReq.allowVibration:type_name -> openim.protobuf.Int32Value - 47, // 12: openim.chat.UpdateUserInfoReq.globalRecvMsgOpt:type_name -> openim.protobuf.Int32Value - 47, // 13: openim.chat.UpdateUserInfoReq.RegisterType:type_name -> openim.protobuf.Int32Value - 49, // 14: openim.chat.FindUserPublicInfoResp.users:type_name -> openim.chat.common.UserPublicInfo - 50, // 15: openim.chat.SearchUserPublicInfoReq.pagination:type_name -> openim.sdkws.RequestPagination - 49, // 16: openim.chat.SearchUserPublicInfoResp.users:type_name -> openim.chat.common.UserPublicInfo - 51, // 17: openim.chat.FindUserFullInfoResp.users:type_name -> openim.chat.common.UserFullInfo + 50, // 0: openim.chat.UpdateUserInfoReq.account:type_name -> openim.protobuf.StringValue + 50, // 1: openim.chat.UpdateUserInfoReq.phoneNumber:type_name -> openim.protobuf.StringValue + 50, // 2: openim.chat.UpdateUserInfoReq.areaCode:type_name -> openim.protobuf.StringValue + 50, // 3: openim.chat.UpdateUserInfoReq.email:type_name -> openim.protobuf.StringValue + 50, // 4: openim.chat.UpdateUserInfoReq.nickname:type_name -> openim.protobuf.StringValue + 50, // 5: openim.chat.UpdateUserInfoReq.faceURL:type_name -> openim.protobuf.StringValue + 51, // 6: openim.chat.UpdateUserInfoReq.gender:type_name -> openim.protobuf.Int32Value + 51, // 7: openim.chat.UpdateUserInfoReq.level:type_name -> openim.protobuf.Int32Value + 52, // 8: openim.chat.UpdateUserInfoReq.birth:type_name -> openim.protobuf.Int64Value + 51, // 9: openim.chat.UpdateUserInfoReq.allowAddFriend:type_name -> openim.protobuf.Int32Value + 51, // 10: openim.chat.UpdateUserInfoReq.allowBeep:type_name -> openim.protobuf.Int32Value + 51, // 11: openim.chat.UpdateUserInfoReq.allowVibration:type_name -> openim.protobuf.Int32Value + 51, // 12: openim.chat.UpdateUserInfoReq.globalRecvMsgOpt:type_name -> openim.protobuf.Int32Value + 51, // 13: openim.chat.UpdateUserInfoReq.RegisterType:type_name -> openim.protobuf.Int32Value + 53, // 14: openim.chat.FindUserPublicInfoResp.users:type_name -> openim.chat.common.UserPublicInfo + 54, // 15: openim.chat.SearchUserPublicInfoReq.pagination:type_name -> openim.sdkws.RequestPagination + 53, // 16: openim.chat.SearchUserPublicInfoResp.users:type_name -> openim.chat.common.UserPublicInfo + 55, // 17: openim.chat.FindUserFullInfoResp.users:type_name -> openim.chat.common.UserFullInfo 13, // 18: openim.chat.RegisterUserReq.user:type_name -> openim.chat.RegisterUserInfo 13, // 19: openim.chat.AddUserAccountReq.user:type_name -> openim.chat.RegisterUserInfo - 43, // 20: openim.chat.FindUserAccountResp.userAccountMap:type_name -> openim.chat.FindUserAccountResp.UserAccountMapEntry - 44, // 21: openim.chat.FindAccountUserResp.accountUserMap:type_name -> openim.chat.FindAccountUserResp.AccountUserMapEntry - 49, // 22: openim.chat.SignalRecord.inviterUserList:type_name -> openim.chat.common.UserPublicInfo - 50, // 23: openim.chat.SearchUserFullInfoReq.pagination:type_name -> openim.sdkws.RequestPagination - 51, // 24: openim.chat.SearchUserFullInfoResp.users:type_name -> openim.chat.common.UserFullInfo - 45, // 25: openim.chat.UserLoginCountResp.count:type_name -> openim.chat.UserLoginCountResp.CountEntry - 50, // 26: openim.chat.SearchUserInfoReq.pagination:type_name -> openim.sdkws.RequestPagination - 51, // 27: openim.chat.SearchUserInfoResp.users:type_name -> openim.chat.common.UserFullInfo + 47, // 20: openim.chat.FindUserAccountResp.userAccountMap:type_name -> openim.chat.FindUserAccountResp.UserAccountMapEntry + 48, // 21: openim.chat.FindAccountUserResp.accountUserMap:type_name -> openim.chat.FindAccountUserResp.AccountUserMapEntry + 53, // 22: openim.chat.SignalRecord.inviterUserList:type_name -> openim.chat.common.UserPublicInfo + 54, // 23: openim.chat.SearchUserFullInfoReq.pagination:type_name -> openim.sdkws.RequestPagination + 55, // 24: openim.chat.SearchUserFullInfoResp.users:type_name -> openim.chat.common.UserFullInfo + 49, // 25: openim.chat.UserLoginCountResp.count:type_name -> openim.chat.UserLoginCountResp.CountEntry + 54, // 26: openim.chat.SearchUserInfoReq.pagination:type_name -> openim.sdkws.RequestPagination + 55, // 27: openim.chat.SearchUserInfoResp.users:type_name -> openim.chat.common.UserFullInfo 13, // 28: openim.chat.CheckUserExistReq.user:type_name -> openim.chat.RegisterUserInfo 1, // 29: openim.chat.chat.UpdateUserInfo:input_type -> openim.chat.UpdateUserInfoReq 16, // 30: openim.chat.chat.AddUserAccount:input_type -> openim.chat.AddUserAccountReq @@ -3366,28 +3561,32 @@ var file_chat_chat_proto_depIdxs = []int32{ 32, // 46: openim.chat.chat.UserLoginCount:input_type -> openim.chat.UserLoginCountReq 35, // 47: openim.chat.chat.SearchUserInfo:input_type -> openim.chat.SearchUserInfoReq 37, // 48: openim.chat.chat.GetTokenForVideoMeeting:input_type -> openim.chat.GetTokenForVideoMeetingReq - 2, // 49: openim.chat.chat.UpdateUserInfo:output_type -> openim.chat.UpdateUserInfoResp - 17, // 50: openim.chat.chat.AddUserAccount:output_type -> openim.chat.AddUserAccountResp - 6, // 51: openim.chat.chat.SearchUserPublicInfo:output_type -> openim.chat.SearchUserPublicInfoResp - 4, // 52: openim.chat.chat.FindUserPublicInfo:output_type -> openim.chat.FindUserPublicInfoResp - 31, // 53: openim.chat.chat.SearchUserFullInfo:output_type -> openim.chat.SearchUserFullInfoResp - 8, // 54: openim.chat.chat.FindUserFullInfo:output_type -> openim.chat.FindUserFullInfoResp - 10, // 55: openim.chat.chat.SendVerifyCode:output_type -> openim.chat.SendVerifyCodeResp - 12, // 56: openim.chat.chat.VerifyCode:output_type -> openim.chat.VerifyCodeResp - 15, // 57: openim.chat.chat.RegisterUser:output_type -> openim.chat.RegisterUserResp - 34, // 58: openim.chat.chat.Login:output_type -> openim.chat.LoginResp - 20, // 59: openim.chat.chat.ResetPassword:output_type -> openim.chat.ResetPasswordResp - 22, // 60: openim.chat.chat.ChangePassword:output_type -> openim.chat.ChangePasswordResp - 40, // 61: openim.chat.chat.CheckUserExist:output_type -> openim.chat.CheckUserExistResp - 42, // 62: openim.chat.chat.DelUserAccount:output_type -> openim.chat.DelUserAccountResp - 24, // 63: openim.chat.chat.FindUserAccount:output_type -> openim.chat.FindUserAccountResp - 26, // 64: openim.chat.chat.FindAccountUser:output_type -> openim.chat.FindAccountUserResp - 29, // 65: openim.chat.chat.OpenIMCallback:output_type -> openim.chat.OpenIMCallbackResp - 33, // 66: openim.chat.chat.UserLoginCount:output_type -> openim.chat.UserLoginCountResp - 36, // 67: openim.chat.chat.SearchUserInfo:output_type -> openim.chat.SearchUserInfoResp - 38, // 68: openim.chat.chat.GetTokenForVideoMeeting:output_type -> openim.chat.GetTokenForVideoMeetingResp - 49, // [49:69] is the sub-list for method output_type - 29, // [29:49] is the sub-list for method input_type + 43, // 49: openim.chat.chat.SetAllowRegister:input_type -> openim.chat.SetAllowRegisterReq + 45, // 50: openim.chat.chat.GetAllowRegister:input_type -> openim.chat.GetAllowRegisterReq + 2, // 51: openim.chat.chat.UpdateUserInfo:output_type -> openim.chat.UpdateUserInfoResp + 17, // 52: openim.chat.chat.AddUserAccount:output_type -> openim.chat.AddUserAccountResp + 6, // 53: openim.chat.chat.SearchUserPublicInfo:output_type -> openim.chat.SearchUserPublicInfoResp + 4, // 54: openim.chat.chat.FindUserPublicInfo:output_type -> openim.chat.FindUserPublicInfoResp + 31, // 55: openim.chat.chat.SearchUserFullInfo:output_type -> openim.chat.SearchUserFullInfoResp + 8, // 56: openim.chat.chat.FindUserFullInfo:output_type -> openim.chat.FindUserFullInfoResp + 10, // 57: openim.chat.chat.SendVerifyCode:output_type -> openim.chat.SendVerifyCodeResp + 12, // 58: openim.chat.chat.VerifyCode:output_type -> openim.chat.VerifyCodeResp + 15, // 59: openim.chat.chat.RegisterUser:output_type -> openim.chat.RegisterUserResp + 34, // 60: openim.chat.chat.Login:output_type -> openim.chat.LoginResp + 20, // 61: openim.chat.chat.ResetPassword:output_type -> openim.chat.ResetPasswordResp + 22, // 62: openim.chat.chat.ChangePassword:output_type -> openim.chat.ChangePasswordResp + 40, // 63: openim.chat.chat.CheckUserExist:output_type -> openim.chat.CheckUserExistResp + 42, // 64: openim.chat.chat.DelUserAccount:output_type -> openim.chat.DelUserAccountResp + 24, // 65: openim.chat.chat.FindUserAccount:output_type -> openim.chat.FindUserAccountResp + 26, // 66: openim.chat.chat.FindAccountUser:output_type -> openim.chat.FindAccountUserResp + 29, // 67: openim.chat.chat.OpenIMCallback:output_type -> openim.chat.OpenIMCallbackResp + 33, // 68: openim.chat.chat.UserLoginCount:output_type -> openim.chat.UserLoginCountResp + 36, // 69: openim.chat.chat.SearchUserInfo:output_type -> openim.chat.SearchUserInfoResp + 38, // 70: openim.chat.chat.GetTokenForVideoMeeting:output_type -> openim.chat.GetTokenForVideoMeetingResp + 44, // 71: openim.chat.chat.SetAllowRegister:output_type -> openim.chat.SetAllowRegisterResp + 46, // 72: openim.chat.chat.GetAllowRegister:output_type -> openim.chat.GetAllowRegisterResp + 51, // [51:73] is the sub-list for method output_type + 29, // [29:51] is the sub-list for method input_type 29, // [29:29] is the sub-list for extension type_name 29, // [29:29] is the sub-list for extension extendee 0, // [0:29] is the sub-list for field type_name @@ -3915,6 +4114,54 @@ func file_chat_chat_proto_init() { return nil } } + file_chat_chat_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SetAllowRegisterReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SetAllowRegisterResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetAllowRegisterReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_chat_chat_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetAllowRegisterResp); 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{ @@ -3922,7 +4169,7 @@ func file_chat_chat_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_chat_chat_proto_rawDesc, NumEnums: 0, - NumMessages: 46, + NumMessages: 50, NumExtensions: 0, NumServices: 1, }, @@ -3973,6 +4220,8 @@ type ChatClient interface { SearchUserInfo(ctx context.Context, in *SearchUserInfoReq, opts ...grpc.CallOption) (*SearchUserInfoResp, error) // Audio/video call and video meeting GetTokenForVideoMeeting(ctx context.Context, in *GetTokenForVideoMeetingReq, opts ...grpc.CallOption) (*GetTokenForVideoMeetingResp, error) + SetAllowRegister(ctx context.Context, in *SetAllowRegisterReq, opts ...grpc.CallOption) (*SetAllowRegisterResp, error) + GetAllowRegister(ctx context.Context, in *GetAllowRegisterReq, opts ...grpc.CallOption) (*GetAllowRegisterResp, error) } type chatClient struct { @@ -4163,6 +4412,24 @@ func (c *chatClient) GetTokenForVideoMeeting(ctx context.Context, in *GetTokenFo return out, nil } +func (c *chatClient) SetAllowRegister(ctx context.Context, in *SetAllowRegisterReq, opts ...grpc.CallOption) (*SetAllowRegisterResp, error) { + out := new(SetAllowRegisterResp) + err := c.cc.Invoke(ctx, "/openim.chat.chat/SetAllowRegister", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *chatClient) GetAllowRegister(ctx context.Context, in *GetAllowRegisterReq, opts ...grpc.CallOption) (*GetAllowRegisterResp, error) { + out := new(GetAllowRegisterResp) + err := c.cc.Invoke(ctx, "/openim.chat.chat/GetAllowRegister", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // ChatServer is the server API for Chat service. type ChatServer interface { // Edit personal information - called by the user or an administrator @@ -4190,6 +4457,8 @@ type ChatServer interface { SearchUserInfo(context.Context, *SearchUserInfoReq) (*SearchUserInfoResp, error) // Audio/video call and video meeting GetTokenForVideoMeeting(context.Context, *GetTokenForVideoMeetingReq) (*GetTokenForVideoMeetingResp, error) + SetAllowRegister(context.Context, *SetAllowRegisterReq) (*SetAllowRegisterResp, error) + GetAllowRegister(context.Context, *GetAllowRegisterReq) (*GetAllowRegisterResp, error) } // UnimplementedChatServer can be embedded to have forward compatible implementations. @@ -4256,6 +4525,12 @@ func (*UnimplementedChatServer) SearchUserInfo(context.Context, *SearchUserInfoR func (*UnimplementedChatServer) GetTokenForVideoMeeting(context.Context, *GetTokenForVideoMeetingReq) (*GetTokenForVideoMeetingResp, error) { return nil, status.Errorf(codes.Unimplemented, "method GetTokenForVideoMeeting not implemented") } +func (*UnimplementedChatServer) SetAllowRegister(context.Context, *SetAllowRegisterReq) (*SetAllowRegisterResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetAllowRegister not implemented") +} +func (*UnimplementedChatServer) GetAllowRegister(context.Context, *GetAllowRegisterReq) (*GetAllowRegisterResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetAllowRegister not implemented") +} func RegisterChatServer(s *grpc.Server, srv ChatServer) { s.RegisterService(&_Chat_serviceDesc, srv) @@ -4621,6 +4896,42 @@ func _Chat_GetTokenForVideoMeeting_Handler(srv interface{}, ctx context.Context, return interceptor(ctx, in, info, handler) } +func _Chat_SetAllowRegister_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SetAllowRegisterReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).SetAllowRegister(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/openim.chat.chat/SetAllowRegister", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).SetAllowRegister(ctx, req.(*SetAllowRegisterReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chat_GetAllowRegister_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetAllowRegisterReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChatServer).GetAllowRegister(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/openim.chat.chat/GetAllowRegister", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChatServer).GetAllowRegister(ctx, req.(*GetAllowRegisterReq)) + } + return interceptor(ctx, in, info, handler) +} + var _Chat_serviceDesc = grpc.ServiceDesc{ ServiceName: "openim.chat.chat", HandlerType: (*ChatServer)(nil), @@ -4705,6 +5016,14 @@ var _Chat_serviceDesc = grpc.ServiceDesc{ MethodName: "GetTokenForVideoMeeting", Handler: _Chat_GetTokenForVideoMeeting_Handler, }, + { + MethodName: "SetAllowRegister", + Handler: _Chat_SetAllowRegister_Handler, + }, + { + MethodName: "GetAllowRegister", + Handler: _Chat_GetAllowRegister_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "chat/chat.proto", diff --git a/pkg/protocol/chat/chat.proto b/pkg/protocol/chat/chat.proto index c66bbd62c..45781533f 100644 --- a/pkg/protocol/chat/chat.proto +++ b/pkg/protocol/chat/chat.proto @@ -274,6 +274,21 @@ message DelUserAccountReq { } message DelUserAccountResp {} +message SetAllowRegisterReq { + bool allowRegister = 1; +} + +message SetAllowRegisterResp { +} + +message GetAllowRegisterReq { +} + +message GetAllowRegisterResp { + bool allowRegister = 1; +} + + service chat { // Edit personal information - called by the user or an administrator rpc UpdateUserInfo(UpdateUserInfoReq) returns (UpdateUserInfoResp); @@ -305,4 +320,7 @@ service chat { // Audio/video call and video meeting rpc GetTokenForVideoMeeting(GetTokenForVideoMeetingReq) returns (GetTokenForVideoMeetingResp); + + rpc SetAllowRegister(SetAllowRegisterReq) returns(SetAllowRegisterResp); + rpc GetAllowRegister(GetAllowRegisterReq) returns(GetAllowRegisterResp); } diff --git a/pkg/protocol/gen.cmd b/pkg/protocol/gen.cmd index ac7ae372e..b837c1d57 100644 --- a/pkg/protocol/gen.cmd +++ b/pkg/protocol/gen.cmd @@ -9,4 +9,9 @@ for %%i in (%PROTO_NAMES%) do ( protoc --go_out=plugins=grpc:./%%i --go_opt=module=github.com/openimsdk/chat/pkg/protocol/%%i %%i/%%i.proto ) +rem Replace "omitempty" in *.pb.go files with UTF-8 encoding +for /r %%f in (*.pb.go) do ( + powershell -Command "(Get-Content -Path '%%f' -Encoding UTF8) -replace ',omitempty\"`"', '\"`"' | Set-Content -Path '%%f' -Encoding UTF8" +) + endlocal diff --git a/pkg/protocol/sdkws/sdkws.proto b/pkg/protocol/sdkws/sdkws.proto index 57301c5be..6a55e7f7f 100644 --- a/pkg/protocol/sdkws/sdkws.proto +++ b/pkg/protocol/sdkws/sdkws.proto @@ -389,7 +389,6 @@ message FriendApplicationRejectedTips { FromToUserID fromToUserID = 1; //from: rejecter; to: requester string handleMsg = 2; } -} // FromUserID Added a friend ToUserID message FriendAddedTips { From 15b1fbb739d80a4403c504a23c5a103c4a1f5adf Mon Sep 17 00:00:00 2001 From: icey-yu <119291641+icey-yu@users.noreply.github.com> Date: Wed, 16 Oct 2024 11:42:34 +0800 Subject: [PATCH 06/36] Migration attribute data to credential (#584) * cherry-pick * chore: protocol * chore: user register and update * chore: credential * fix: cherry-pick * chore: user register and update * feat: register pb * fix: cherry-pick * feat: login * feat: check param * fix: check param * fix: protocol * fix: cherry-pick * fix: cherry-pick * fix: old data in attribute to credential * fix: old data in attribute to credential --- start-config.yml | 1 + tools/attribute-to-credential/main.go | 153 ++++++++++++++++++++++++++ tools/dataversion/data_version.go | 50 +++++++++ 3 files changed, 204 insertions(+) create mode 100644 tools/attribute-to-credential/main.go create mode 100644 tools/dataversion/data_version.go diff --git a/start-config.yml b/start-config.yml index b5b8ddc55..0d6707834 100644 --- a/start-config.yml +++ b/start-config.yml @@ -5,4 +5,5 @@ serviceBinaries: admin-rpc: 1 toolBinaries: - check-component + - attribute-to-credential maxFileDescriptors: 10000 diff --git a/tools/attribute-to-credential/main.go b/tools/attribute-to-credential/main.go new file mode 100644 index 000000000..315a3c229 --- /dev/null +++ b/tools/attribute-to-credential/main.go @@ -0,0 +1,153 @@ +package main + +import ( + "context" + "flag" + "fmt" + "github.com/openimsdk/chat/internal/rpc/chat" + "github.com/openimsdk/chat/pkg/common/cmd" + "github.com/openimsdk/chat/pkg/common/config" + "github.com/openimsdk/chat/pkg/common/constant" + table "github.com/openimsdk/chat/pkg/common/db/table/chat" + "github.com/openimsdk/chat/tools/dataversion" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/system/program" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "path/filepath" +) + +const ( + credentialKey = "credential" + credentialVersion = 1 + + attributeCollection = "attribute" + credentialCollection = "credential" + pageNum = 1000 +) + +func initConfig(configDir string) (*config.Mongo, error) { + var ( + mongoConfig = &config.Mongo{} + ) + err := config.LoadConfig(filepath.Join(configDir, cmd.MongodbConfigFileName), cmd.ConfigEnvPrefixMap[cmd.MongodbConfigFileName], mongoConfig) + if err != nil { + return nil, err + } + + return mongoConfig, nil +} + +func pageGetAttribute(ctx context.Context, coll *mongo.Collection, pagination *sdkws.RequestPagination) (int64, []*table.Attribute, error) { + return mongoutil.FindPage[*table.Attribute](ctx, coll, bson.M{}, pagination) +} + +func doAttributeToCredential() error { + var index int + var configDir string + flag.IntVar(&index, "i", 0, "Index number") + defaultConfigDir := filepath.Join("..", "..", "..", "..", "..", "config") + flag.StringVar(&configDir, "c", defaultConfigDir, "Configuration dir") + flag.Parse() + + fmt.Printf("Index: %d, Config Path: %s\n", index, configDir) + + mongoConfig, err := initConfig(configDir) + if err != nil { + return err + } + + ctx := context.Background() + + mgocli, err := mongoutil.NewMongoDB(ctx, mongoConfig.Build()) + if err != nil { + return err + } + + versionColl := mgocli.GetDB().Collection(dataversion.Collection) + converted, err := dataversion.CheckVersion(versionColl, credentialKey, credentialVersion) + if err != nil { + return err + } + if converted { + fmt.Println("[credential] credential data has been converted") + return nil + } + + attrColl := mgocli.GetDB().Collection(attributeCollection) + credColl := mgocli.GetDB().Collection(credentialCollection) + + pagination := &sdkws.RequestPagination{ + PageNumber: 1, + ShowNumber: pageNum, + } + tx := mgocli.GetTx() + if err = tx.Transaction(ctx, func(ctx context.Context) error { + for { + total, attrs, err := pageGetAttribute(ctx, attrColl, pagination) + if err != nil { + return err + } + credentials := make([]*table.Credential, 0, pageNum*3) + for _, attr := range attrs { + if attr.Email != "" { + credentials = append(credentials, &table.Credential{ + UserID: attr.UserID, + Account: attr.Email, + Type: constant.CredentialEmail, + AllowChange: true, + }) + } + if attr.Account != "" { + credentials = append(credentials, &table.Credential{ + UserID: attr.UserID, + Account: attr.Account, + Type: constant.CredentialAccount, + AllowChange: true, + }) + } + if attr.PhoneNumber != "" && attr.AreaCode != "" { + credentials = append(credentials, &table.Credential{ + UserID: attr.UserID, + Account: chat.BuildCredentialPhone(attr.AreaCode, attr.PhoneNumber), + Type: constant.CredentialPhone, + AllowChange: true, + }) + } + + } + for _, credential := range credentials { + err = mongoutil.UpdateOne(ctx, credColl, bson.M{ + "user_id": credential.UserID, + "type": credential.Type, + }, bson.M{ + "$set": credential, + }, false, options.Update().SetUpsert(true)) + if err != nil { + return err + } + } + + pagination.PageNumber++ + if total < pageNum { + break + } + } + return nil + }); err != nil { + return err + } + if err := dataversion.SetVersion(versionColl, credentialKey, credentialVersion); err != nil { + return fmt.Errorf("set mongodb credential version %w", err) + } + fmt.Println("[credential] update old data to credential success") + return nil +} + +func main() { + if err := doAttributeToCredential(); err != nil { + program.ExitWithError(err) + } +} diff --git a/tools/dataversion/data_version.go b/tools/dataversion/data_version.go new file mode 100644 index 000000000..8a1bb8396 --- /dev/null +++ b/tools/dataversion/data_version.go @@ -0,0 +1,50 @@ +package dataversion + +import ( + "context" + "errors" + "fmt" + "github.com/openimsdk/tools/db/mongoutil" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "strconv" + "time" +) + +const ( + Collection = "data_version" +) + +func CheckVersion(coll *mongo.Collection, key string, currentVersion int) (converted bool, err error) { + type VersionTable struct { + Key string `bson:"key"` + Value string `bson:"value"` + } + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + res, err := mongoutil.FindOne[VersionTable](ctx, coll, bson.M{"key": key}) + if err == nil { + ver, err := strconv.Atoi(res.Value) + if err != nil { + return false, fmt.Errorf("version %s parse error %w", res.Value, err) + } + if ver >= currentVersion { + return true, nil + } + return false, nil + } else if errors.Is(err, mongo.ErrNoDocuments) { + return false, nil + } else { + return false, err + } +} + +func SetVersion(coll *mongo.Collection, key string, version int) error { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + option := options.Update().SetUpsert(true) + filter := bson.M{"key": key, "value": strconv.Itoa(version)} + update := bson.M{"$set": bson.M{"key": key, "value": strconv.Itoa(version)}} + return mongoutil.UpdateOne(ctx, coll, filter, update, false, option) +} From d5d246ff25b8cecfe1d09153fdc0d77d8fc1c36d Mon Sep 17 00:00:00 2001 From: icey-yu <119291641+icey-yu@users.noreply.github.com> Date: Fri, 18 Oct 2024 10:09:32 +0800 Subject: [PATCH 07/36] fix: update user (#586) --- pkg/common/db/model/chat/credential.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pkg/common/db/model/chat/credential.go b/pkg/common/db/model/chat/credential.go index 7564c45ef..5a389b3e5 100644 --- a/pkg/common/db/model/chat/credential.go +++ b/pkg/common/db/model/chat/credential.go @@ -2,14 +2,13 @@ package chat import ( "context" - "go.mongodb.org/mongo-driver/mongo/options" - "github.com/openimsdk/chat/pkg/common/db/table/chat" "github.com/openimsdk/tools/db/mongoutil" "github.com/openimsdk/tools/db/pagination" "github.com/openimsdk/tools/errs" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" ) func NewCredential(db *mongo.Database) (chat.CredentialInterface, error) { @@ -128,6 +127,9 @@ func (o *Credential) Delete(ctx context.Context, userIDs []string) error { } func (o *Credential) DeleteByUserIDType(ctx context.Context, credentials ...*chat.Credential) error { + if len(credentials) == 0 { + return nil + } var filters []bson.M for _, credential := range credentials { filters = append(filters, bson.M{ From 79f3f03217ba3b5cdcedc8ef97457eaf373c89fd Mon Sep 17 00:00:00 2001 From: icey-yu <119291641+icey-yu@users.noreply.github.com> Date: Fri, 18 Oct 2024 15:36:02 +0800 Subject: [PATCH 08/36] fix: add user (#590) --- internal/api/admin/admin.go | 9 +++++++-- pkg/common/imapi/caller.go | 25 +++++++++++++------------ 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/internal/api/admin/admin.go b/internal/api/admin/admin.go index 6bc4b921c..bafb5cdce 100644 --- a/internal/api/admin/admin.go +++ b/internal/api/admin/admin.go @@ -153,7 +153,13 @@ func (o *Api) AddUserAccount(c *gin.Context) { FaceURL: req.User.FaceURL, CreateTime: time.Now().UnixMilli(), } - err = o.imApiCaller.RegisterUser(c, []*sdkws.UserInfo{userInfo}) + imToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) + if err != nil { + apiresp.GinError(c, err) + return + } + ctx := o.WithAdminUser(mctx.WithApiToken(c, imToken)) + err = o.imApiCaller.RegisterUser(ctx, []*sdkws.UserInfo{userInfo}) if err != nil { apiresp.GinError(c, err) return @@ -166,7 +172,6 @@ func (o *Api) AddUserAccount(c *gin.Context) { _ = o.imApiCaller.InviteToGroup(c, req.User.UserID, resp.GroupIDs) } apiresp.GinSuccess(c, nil) - } func (o *Api) DelAdminAccount(c *gin.Context) { diff --git a/pkg/common/imapi/caller.go b/pkg/common/imapi/caller.go index 24b9d545d..88f8f9141 100644 --- a/pkg/common/imapi/caller.go +++ b/pkg/common/imapi/caller.go @@ -2,12 +2,11 @@ package imapi import ( "context" + "github.com/openimsdk/tools/log" "sync" "time" "github.com/openimsdk/chat/pkg/eerrs" - "github.com/openimsdk/tools/log" - "github.com/openimsdk/protocol/auth" "github.com/openimsdk/protocol/constant" constantpb "github.com/openimsdk/protocol/constant" @@ -61,18 +60,20 @@ func (c *Caller) ImportFriend(ctx context.Context, ownerUserID string, friendUse } func (c *Caller) ImAdminTokenWithDefaultAdmin(ctx context.Context) (string, error) { - c.lock.Lock() - defer c.lock.Unlock() if c.token == "" || c.timeout.Before(time.Now()) { - userID := c.defaultIMUserID - token, err := c.GetAdminToken(ctx, userID) - if err != nil { - log.ZError(ctx, "get im admin token", err, "userID", userID) - return "", err + c.lock.Lock() + if c.token == "" || c.timeout.Before(time.Now()) { + userID := c.defaultIMUserID + token, err := c.GetAdminToken(ctx, userID) + if err != nil { + log.ZError(ctx, "get im admin token", err, "userID", userID) + return "", err + } + log.ZDebug(ctx, "get im admin token", "userID", userID) + c.token = token + c.timeout = time.Now().Add(time.Minute * 5) } - log.ZDebug(ctx, "get im admin token", "userID", userID) - c.token = token - c.timeout = time.Now().Add(time.Minute * 5) + c.lock.Unlock() } return c.token, nil } From 90ec55dc1b56e20c5ab24287df4f852d19ad5877 Mon Sep 17 00:00:00 2001 From: icey-yu <119291641+icey-yu@users.noreply.github.com> Date: Fri, 18 Oct 2024 15:48:04 +0800 Subject: [PATCH 09/36] fix: search user && add user (#593) --- internal/api/admin/admin.go | 21 +++++---------------- pkg/common/db/model/chat/attribute.go | 1 + 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/internal/api/admin/admin.go b/internal/api/admin/admin.go index bafb5cdce..df0d8531e 100644 --- a/internal/api/admin/admin.go +++ b/internal/api/admin/admin.go @@ -142,35 +142,24 @@ func (o *Api) AddUserAccount(c *gin.Context) { apiresp.GinError(c, err) return } - if _, err := o.chatClient.AddUserAccount(c, req); err != nil { + ip, err := o.GetClientIP(c) + if err != nil { apiresp.GinError(c, err) return } - - userInfo := &sdkws.UserInfo{ - UserID: req.User.UserID, - Nickname: req.User.Nickname, - FaceURL: req.User.FaceURL, - CreateTime: time.Now().UnixMilli(), - } imToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) if err != nil { apiresp.GinError(c, err) return } + ctx := o.WithAdminUser(mctx.WithApiToken(c, imToken)) - err = o.imApiCaller.RegisterUser(ctx, []*sdkws.UserInfo{userInfo}) + + err = o.registerChatUser(ctx, ip, []*chat.RegisterUserInfo{req.User}) if err != nil { - apiresp.GinError(c, err) return } - if resp, err := o.adminClient.FindDefaultFriend(c, &admin.FindDefaultFriendReq{}); err == nil { - _ = o.imApiCaller.ImportFriend(c, req.User.UserID, resp.UserIDs) - } - if resp, err := o.adminClient.FindDefaultGroup(c, &admin.FindDefaultGroupReq{}); err == nil { - _ = o.imApiCaller.InviteToGroup(c, req.User.UserID, resp.GroupIDs) - } apiresp.GinSuccess(c, nil) } diff --git a/pkg/common/db/model/chat/attribute.go b/pkg/common/db/model/chat/attribute.go index 9b83b2df3..3597dd4af 100644 --- a/pkg/common/db/model/chat/attribute.go +++ b/pkg/common/db/model/chat/attribute.go @@ -140,6 +140,7 @@ func (o *Attribute) SearchNormalUser(ctx context.Context, keyword string, forbid {"account": bson.M{"$regex": keyword, "$options": "i"}}, {"nickname": bson.M{"$regex": keyword, "$options": "i"}}, {"phone_number": bson.M{"$regex": keyword, "$options": "i"}}, + {"email": bson.M{"$regex": keyword, "$options": "i"}}, } } return mongoutil.FindPage[*chat.Attribute](ctx, o.coll, filter, pagination) From 7f8984b854fb79b6a3cff217aa07396906d44609 Mon Sep 17 00:00:00 2001 From: icey-yu <119291641+icey-yu@users.noreply.github.com> Date: Mon, 21 Oct 2024 14:27:21 +0800 Subject: [PATCH 10/36] fix: Reset password by email failed (#595) * fix: ResetPasswordReq pb * fix: reset psw error * Revert "fix: ResetPasswordReq pb" This reverts commit 7e884dc225a523e219333332859ec236a2b3fdd1. --- internal/rpc/chat/password.go | 31 ++++++++++++++++--------------- pkg/common/db/database/chat.go | 3 +++ 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/internal/rpc/chat/password.go b/internal/rpc/chat/password.go index 7c9657a0a..73d34a36f 100644 --- a/internal/rpc/chat/password.go +++ b/internal/rpc/chat/password.go @@ -16,7 +16,6 @@ package chat import ( "context" - "github.com/openimsdk/tools/errs" "github.com/openimsdk/chat/pkg/common/constant" @@ -28,6 +27,11 @@ func (o *chatSvr) ResetPassword(ctx context.Context, req *chat.ResetPasswordReq) if req.Password == "" { return nil, errs.ErrArgs.WrapMsg("password must be set") } + if req.AreaCode == "" || req.PhoneNumber == "" { + if !(req.AreaCode == "" && req.PhoneNumber == "") { + return nil, errs.ErrArgs.WrapMsg("area code and phone number must set together") + } + } var verifyCodeID string var err error if req.Email == "" { @@ -39,22 +43,19 @@ func (o *chatSvr) ResetPassword(ctx context.Context, req *chat.ResetPasswordReq) if err != nil { return nil, err } - + var account string if req.Email == "" { - attribute, err := o.Database.TakeAttributeByPhone(ctx, req.AreaCode, req.PhoneNumber) - if err != nil { - return nil, err - } - err = o.Database.UpdatePasswordAndDeleteVerifyCode(ctx, attribute.UserID, req.Password, verifyCodeID) + account = BuildCredentialPhone(req.AreaCode, req.PhoneNumber) } else { - attribute, err := o.Database.TakeAttributeByEmail(ctx, req.Email) - if err != nil { - return nil, err - } - err = o.Database.UpdatePasswordAndDeleteVerifyCode(ctx, attribute.UserID, req.Password, verifyCodeID) - if err != nil { - return nil, err - } + account = req.Email + } + cred, err := o.Database.TakeCredentialByAccount(ctx, account) + if err != nil { + return nil, err + } + err = o.Database.UpdatePasswordAndDeleteVerifyCode(ctx, cred.UserID, req.Password, verifyCodeID) + if err != nil { + return nil, err } return &chat.ResetPasswordResp{}, nil } diff --git a/pkg/common/db/database/chat.go b/pkg/common/db/database/chat.go index 55acd558a..5898fd73e 100644 --- a/pkg/common/db/database/chat.go +++ b/pkg/common/db/database/chat.go @@ -255,6 +255,9 @@ func (o *ChatDatabase) UpdatePasswordAndDeleteVerifyCode(ctx context.Context, us if err := o.account.UpdatePassword(ctx, userID, password); err != nil { return err } + if codeID == "" { + return nil + } if err := o.verifyCode.Delete(ctx, codeID); err != nil { return err } From ac82ec02e0993955f2c72c77c34fd3e79ec133fa Mon Sep 17 00:00:00 2001 From: icey-yu <119291641+icey-yu@users.noreply.github.com> Date: Mon, 21 Oct 2024 16:35:54 +0800 Subject: [PATCH 11/36] fix: login check (#597) --- internal/rpc/chat/login.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/internal/rpc/chat/login.go b/internal/rpc/chat/login.go index e672ccddf..5c4007d4d 100644 --- a/internal/rpc/chat/login.go +++ b/internal/rpc/chat/login.go @@ -374,9 +374,6 @@ func (o *chatSvr) Login(ctx context.Context, req *chat.LoginReq) (*chat.LoginRes if req.Password == "" && req.VerifyCode == "" { return nil, errs.ErrArgs.WrapMsg("password or code must be set") } - if req.Password == "" { - return nil, errs.ErrArgs.WrapMsg("password must be set") - } var ( err error credential *chatdb.Credential From 27a6e8cef405737c4acc3cd3e96f56e38300d545 Mon Sep 17 00:00:00 2001 From: icey-yu <119291641+icey-yu@users.noreply.github.com> Date: Thu, 24 Oct 2024 11:34:55 +0800 Subject: [PATCH 12/36] fix: SearchFriend can search email (#600) --- pkg/common/db/model/chat/attribute.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/common/db/model/chat/attribute.go b/pkg/common/db/model/chat/attribute.go index 3597dd4af..15112d3d3 100644 --- a/pkg/common/db/model/chat/attribute.go +++ b/pkg/common/db/model/chat/attribute.go @@ -164,6 +164,7 @@ func (o *Attribute) SearchUser(ctx context.Context, keyword string, userIDs []st {"account": bson.M{"$regex": keyword, "$options": "i"}}, {"nickname": bson.M{"$regex": keyword, "$options": "i"}}, {"phone_number": bson.M{"$regex": keyword, "$options": "i"}}, + {"email": bson.M{"$regex": keyword, "$options": "i"}}, } } return mongoutil.FindPage[*chat.Attribute](ctx, o.coll, filter, pagination) From f42ae5766a81847cb0c194a4182ed0244412516a Mon Sep 17 00:00:00 2001 From: icey-yu <119291641+icey-yu@users.noreply.github.com> Date: Thu, 24 Oct 2024 11:19:00 +0800 Subject: [PATCH 13/36] fix: change register error (#602) --- internal/rpc/chat/user.go | 2 +- internal/rpc/chat/utils.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/rpc/chat/user.go b/internal/rpc/chat/user.go index 057cc6d78..c3fc234af 100644 --- a/internal/rpc/chat/user.go +++ b/internal/rpc/chat/user.go @@ -143,7 +143,7 @@ func (o *chatSvr) checkUpdateInfo(ctx context.Context, req *chat.UpdateUserInfoR } _, err := o.Database.TakeCredentialByAccount(ctx, req.Email.GetValue()) if err == nil { - return eerrs.ErrAccountAlreadyRegister.Wrap() + return eerrs.ErrEmailAlreadyRegister.Wrap() } else if !dbutil.IsDBNotFound(err) { return err } diff --git a/internal/rpc/chat/utils.go b/internal/rpc/chat/utils.go index b8c1f1740..41ebd1bc1 100644 --- a/internal/rpc/chat/utils.go +++ b/internal/rpc/chat/utils.go @@ -103,7 +103,7 @@ func (o *chatSvr) checkRegisterInfo(ctx context.Context, user *chat.RegisterUser } _, err := o.Database.TakeAttributeByAccount(ctx, user.Email) if err == nil { - return eerrs.ErrAccountAlreadyRegister.Wrap() + return eerrs.ErrEmailAlreadyRegister.Wrap() } else if !dbutil.IsDBNotFound(err) { return err } From 802c0b327f608afff10431b7dae21348c4efac01 Mon Sep 17 00:00:00 2001 From: icey-yu <119291641+icey-yu@users.noreply.github.com> Date: Thu, 24 Oct 2024 11:45:59 +0800 Subject: [PATCH 14/36] fix: update user email error (#604) --- internal/rpc/chat/update.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/rpc/chat/update.go b/internal/rpc/chat/update.go index 8f69de2f2..13b9b57f1 100644 --- a/internal/rpc/chat/update.go +++ b/internal/rpc/chat/update.go @@ -99,7 +99,7 @@ func ToDBCredentialUpdate(req *chat.UpdateUserInfoReq, allowChange bool) ([]*cha } else { update = append(update, &chatdb.Credential{ UserID: req.UserID, - Account: req.Account.GetValue(), + Account: req.Email.GetValue(), Type: constant.CredentialEmail, AllowChange: allowChange, }) From 7cdb54459e57b7a331e7f4ba7b994bdccca67f33 Mon Sep 17 00:00:00 2001 From: Monet Lee Date: Mon, 25 Nov 2024 10:14:44 +0800 Subject: [PATCH 15/36] build: implement milestone merge and update workflows. (#609) * build: implement milestone merge and update workflows. * update default * update branch. * remove label. --- .../cleanup-after-milestone-prs-merged.yml | 65 ++++++ .github/workflows/merge-from-milestone.yml | 218 ++++++++++++++++++ .../workflows/remove-unused-labels copy.yml | 74 ++++++ .github/workflows/remove-unused-labels.yml | 75 ++++++ .../update-version-file-on-release.yml | 20 +- 5 files changed, 442 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/cleanup-after-milestone-prs-merged.yml create mode 100644 .github/workflows/merge-from-milestone.yml create mode 100644 .github/workflows/remove-unused-labels copy.yml create mode 100644 .github/workflows/remove-unused-labels.yml diff --git a/.github/workflows/cleanup-after-milestone-prs-merged.yml b/.github/workflows/cleanup-after-milestone-prs-merged.yml new file mode 100644 index 000000000..8a3e381d6 --- /dev/null +++ b/.github/workflows/cleanup-after-milestone-prs-merged.yml @@ -0,0 +1,65 @@ +name: Cleanup After Milestone PRs Merged + +on: + pull_request: + types: + - closed + +jobs: + handle_pr: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4.2.0 + + - name: Get the PR title and extract PR numbers + id: extract_pr_numbers + run: | + # Get the PR title + PR_TITLE="${{ github.event.pull_request.title }}" + + echo "PR Title: $PR_TITLE" + + # Extract PR numbers from the title + PR_NUMBERS=$(echo "$PR_TITLE" | grep -oE "#[0-9]+" | tr -d '#' | tr '\n' ' ') + echo "Extracted PR Numbers: $PR_NUMBERS" + + # Save PR numbers to a file + echo "$PR_NUMBERS" > pr_numbers.txt + echo "Saved PR Numbers to pr_numbers.txt" + + # Check if the title matches a specific pattern + if echo "$PR_TITLE" | grep -qE "^deps: Merge( #[0-9]+)+ PRs into .+"; then + echo "proceed=true" >> $GITHUB_OUTPUT + else + echo "proceed=false" >> $GITHUB_OUTPUT + fi + + - name: Use extracted PR numbers and label PRs + if: (steps.extract_pr_numbers.outputs.proceed == 'true' || contains(github.event.pull_request.labels.*.name, 'milestone-merge')) && github.event.pull_request.merged == true + run: | + # Read the previously saved PR numbers + PR_NUMBERS=$(cat pr_numbers.txt) + echo "Using extracted PR Numbers: $PR_NUMBERS" + + # Loop through each PR number and add label + for PR_NUMBER in $PR_NUMBERS; do + echo "Adding 'cherry-picked' label to PR #$PR_NUMBER" + curl -X POST \ + -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + -H "Accept: application/vnd.github+json" \ + https://api.github.com/repos/${{ github.repository }}/issues/$PR_NUMBER/labels \ + -d '{"labels":["cherry-picked"]}' + done + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Delete branch after PR close + if: steps.extract_pr_numbers.outputs.proceed == 'true' || contains(github.event.pull_request.labels.*.name, 'milestone-merge') + run: | + BRANCH_NAME="${{ github.event.pull_request.head.ref }}" + echo "Branch to delete: $BRANCH_NAME" + git push origin --delete "$BRANCH_NAME" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/merge-from-milestone.yml b/.github/workflows/merge-from-milestone.yml new file mode 100644 index 000000000..939c08fcb --- /dev/null +++ b/.github/workflows/merge-from-milestone.yml @@ -0,0 +1,218 @@ +name: Create Pre-Release PR from Milestone + +permissions: + contents: write + pull-requests: write + issues: write + +on: + workflow_dispatch: + inputs: + milestone_name: + description: 'Milestone name to collect closed PRs from' + required: true + default: 'v1.8.3' + target_branch: + description: 'Target branch to merge the consolidated PR' + required: true + default: 'pre-release-v1.8.3' + +env: + MILESTONE_NAME: ${{ github.event.inputs.milestone_name || 'v1.8.3' }} + TARGET_BRANCH: ${{ github.event.inputs.target_branch || 'pre-release-v1.8.3' }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BOT_TOKEN: ${{ secrets.BOT_TOKEN }} + LABEL_NAME: cherry-picked + TEMP_DIR: /tmp # Using /tmp as the temporary directory + +jobs: + cherry_pick_milestone_prs: + runs-on: ubuntu-latest + steps: + - name: Setup temp directory + run: | + # Create the temporary directory and initialize necessary files + mkdir -p ${{ env.TEMP_DIR }} + touch ${{ env.TEMP_DIR }}/pr_numbers.txt + touch ${{ env.TEMP_DIR }}/commit_hashes.txt + touch ${{ env.TEMP_DIR }}/pr_title.txt + touch ${{ env.TEMP_DIR }}/pr_body.txt + touch ${{ env.TEMP_DIR }}/created_pr_number.txt + + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.BOT_TOKEN }} + + - name: Setup Git User for OpenIM-Robot + run: | + # Set up Git credentials for the bot + git config --global user.email "OpenIM-Robot@users.noreply.github.com" + git config --global user.name "OpenIM-Robot" + + - name: Fetch Milestone ID and Filter PR Numbers + env: + MILESTONE_NAME: ${{ env.MILESTONE_NAME }} + run: | + # Fetch milestone details and extract milestone ID + milestones=$(curl -s -H "Authorization: token $BOT_TOKEN" \ + -H "Accept: application/vnd.github+json" \ + "https://api.github.com/repos/${{ github.repository }}/milestones") + milestone_id=$(echo "$milestones" | grep -B3 "\"title\": \"$MILESTONE_NAME\"" | grep '"number":' | head -n1 | grep -o '[0-9]\+') + if [ -z "$milestone_id" ]; then + echo "Milestone '$MILESTONE_NAME' not found. Exiting." + exit 1 + fi + echo "Milestone ID: $milestone_id" + echo "MILESTONE_ID=$milestone_id" >> $GITHUB_ENV + + # Fetch issues for the milestone + issues=$(curl -s -H "Authorization: token $BOT_TOKEN" \ + -H "Accept: application/vnd.github+json" \ + "https://api.github.com/repos/${{ github.repository }}/issues?milestone=$milestone_id&state=closed&per_page=100") + + > ${{ env.TEMP_DIR }}/pr_numbers.txt + + # Filter PRs that do not have the 'cherry-picked' label + for pr_number in $(echo "$issues" | jq -r '.[] | select(.pull_request != null) | .number'); do + labels=$(curl -s -H "Authorization: token $BOT_TOKEN" \ + -H "Accept: application/vnd.github+json" \ + "https://api.github.com/repos/${{ github.repository }}/issues/$pr_number/labels" | jq -r '.[].name') + + if ! echo "$labels" | grep -q "${LABEL_NAME}"; then + echo "PR #$pr_number does not have the 'cherry-picked' label. Adding to the list." + echo "$pr_number" >> ${{ env.TEMP_DIR }}/pr_numbers.txt + else + echo "PR #$pr_number already has the 'cherry-picked' label. Skipping." + fi + done + + # Sort the filtered PR numbers + sort -n ${{ env.TEMP_DIR }}/pr_numbers.txt -o ${{ env.TEMP_DIR }}/pr_numbers.txt + + echo "Filtered and sorted PR numbers:" + cat ${{ env.TEMP_DIR }}/pr_numbers.txt || echo "No closed PR numbers found for milestone." + + - name: Fetch Merge Commits for PRs and Generate Title and Body + run: | + # Ensure the files are initialized + > ${{ env.TEMP_DIR }}/commit_hashes.txt + > ${{ env.TEMP_DIR }}/pr_title.txt + > ${{ env.TEMP_DIR }}/pr_body.txt + + # Write description to the PR body + echo "### Description:" >> ${{ env.TEMP_DIR }}/pr_body.txt + echo "Merging PRs from milestone \`$MILESTONE_NAME\` into target branch \`$TARGET_BRANCH\`." >> ${{ env.TEMP_DIR }}/pr_body.txt + echo "" >> ${{ env.TEMP_DIR }}/pr_body.txt + echo "### Need Merge PRs:" >> ${{ env.TEMP_DIR }}/pr_body.txt + + pr_numbers_in_title="" + + # Process sorted PR numbers and generate commit hashes + for pr_number in $(cat ${{ env.TEMP_DIR }}/pr_numbers.txt); do + echo "Processing PR #$pr_number" + pr_details=$(curl -s -H "Authorization: token $BOT_TOKEN" \ + -H "Accept: application/vnd.github+json" \ + "https://api.github.com/repos/${{ github.repository }}/pulls/$pr_number") + pr_title=$(echo "$pr_details" | jq -r '.title') + merge_commit=$(echo "$pr_details" | jq -r '.merge_commit_sha') + short_commit_hash=$(echo "$merge_commit" | cut -c 1-7) + + # Append PR details to the body + echo "- $pr_title: (#$pr_number) ($short_commit_hash)" >> ${{ env.TEMP_DIR }}/pr_body.txt + + if [ "$merge_commit" != "null" ];then + echo "$merge_commit" >> ${{ env.TEMP_DIR }}/commit_hashes.txt + echo "#$pr_number" >> ${{ env.TEMP_DIR }}/pr_title.txt + pr_numbers_in_title="$pr_numbers_in_title #$pr_number" + fi + done + + commit_hashes=$(cat ${{ env.TEMP_DIR }}/commit_hashes.txt | tr '\n' ' ') + first_commit_hash=$(head -n 1 ${{ env.TEMP_DIR }}/commit_hashes.txt) + cherry_pick_branch="cherry-pick-${first_commit_hash:0:7}" + echo "COMMIT_HASHES=$commit_hashes" >> $GITHUB_ENV + echo "CHERRY_PICK_BRANCH=$cherry_pick_branch" >> $GITHUB_ENV + echo "pr_numbers_in_title=$pr_numbers_in_title" >> $GITHUB_ENV + + - name: Pull and Cherry-pick Commits, Then Push + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BOT_TOKEN: ${{ secrets.BOT_TOKEN }} + run: | + # Fetch and pull the latest changes from the target branch + git fetch origin + git checkout $TARGET_BRANCH + git pull origin $TARGET_BRANCH + + # Create a new branch for cherry-picking + git checkout -b $CHERRY_PICK_BRANCH + + # Cherry-pick the commits and handle conflicts + for commit_hash in $COMMIT_HASHES; do + echo "Attempting to cherry-pick commit $commit_hash" + if ! git cherry-pick "$commit_hash" --strategy=recursive -X theirs; then + echo "Conflict detected for $commit_hash. Resolving with incoming changes." + conflict_files=$(git diff --name-only --diff-filter=U) + echo "Conflicting files:" + echo "$conflict_files" + + for file in $conflict_files; do + if [ -f "$file" ]; then + echo "Resolving conflict for $file" + git add "$file" + else + echo "File $file has been deleted. Skipping." + git rm "$file" + fi + done + + echo "Conflicts resolved. Continuing cherry-pick." + git cherry-pick --continue + else + echo "Cherry-pick successful for commit $commit_hash." + fi + done + + # Push the cherry-pick branch to the repository + git remote set-url origin "https://${BOT_TOKEN}@github.com/${{ github.repository }}.git" + git push origin $CHERRY_PICK_BRANCH --force + + - name: Create Pull Request + run: | + # Prepare and create the PR + pr_title="deps: Merge ${{ env.pr_numbers_in_title }} PRs into $TARGET_BRANCH" + pr_body=$(cat ${{ env.TEMP_DIR }}/pr_body.txt) + + echo "Prepared PR title:" + echo "$pr_title" + echo "Prepared PR body:" + echo "$pr_body" + + # Create the PR using the GitHub API + response=$(curl -s -X POST -H "Authorization: token $BOT_TOKEN" \ + -H "Accept: application/vnd.github+json" \ + https://api.github.com/repos/${{ github.repository }}/pulls \ + -d "$(jq -n --arg title "$pr_title" \ + --arg head "$CHERRY_PICK_BRANCH" \ + --arg base "$TARGET_BRANCH" \ + --arg body "$pr_body" \ + '{title: $title, head: $head, base: $base, body: $body}')") + + pr_number=$(echo "$response" | jq -r '.number') + echo "$pr_number" > ${{ env.TEMP_DIR }}/created_pr_number.txt + echo "Created PR #$pr_number" + + - name: Add Label to Created Pull Request + run: | + # Add 'milestone-merge' label to the created PR + pr_number=$(cat ${{ env.TEMP_DIR }}/created_pr_number.txt) + echo "Adding label to PR #$pr_number" + + curl -s -X POST -H "Authorization: token $GITHUB_TOKEN" \ + -H "Accept: application/vnd.github+json" \ + -d '{"labels": ["milestone-merge"]}' \ + "https://api.github.com/repos/${{ github.repository }}/issues/$pr_number/labels" + + echo "Added 'milestone-merge' label to PR #$pr_number." diff --git a/.github/workflows/remove-unused-labels copy.yml b/.github/workflows/remove-unused-labels copy.yml new file mode 100644 index 000000000..ab80b1f96 --- /dev/null +++ b/.github/workflows/remove-unused-labels copy.yml @@ -0,0 +1,74 @@ +name: Remove Unused Labels +on: + workflow_dispatch: + +jobs: + cleanup: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + contents: read + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Fetch All Issues and PRs + id: fetch_issues_prs + uses: actions/github-script@v7.0.1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const issues = await github.paginate(github.rest.issues.listForRepo, { + owner: context.repo.owner, + repo: context.repo.repo, + state: 'all', + per_page: 100 + }); + + const labelsInUse = new Set(); + issues.forEach(issue => { + issue.labels.forEach(label => { + labelsInUse.add(label.name); + }); + }); + + return JSON.stringify(Array.from(labelsInUse)); + result-encoding: string + + - name: Fetch All Labels + id: fetch_labels + uses: actions/github-script@v7.0.1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const labels = await github.paginate(github.rest.issues.listLabelsForRepo, { + owner: context.repo.owner, + repo: context.repo.repo, + per_page: 100 + }); + + return JSON.stringify(labels.map(label => label.name)); + result-encoding: string + + - name: Remove Unused Labels + uses: actions/github-script@v7.0.1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const labelsInUse = new Set(JSON.parse(process.env.LABELS_IN_USE)); + const allLabels = JSON.parse(process.env.ALL_LABELS); + + const unusedLabels = allLabels.filter(label => !labelsInUse.has(label)); + + for (const label of unusedLabels) { + await github.rest.issues.deleteLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + name: label + }); + console.log(`Deleted label: ${label}`); + } + env: + LABELS_IN_USE: ${{ steps.fetch_issues_prs.outputs.result }} + ALL_LABELS: ${{ steps.fetch_labels.outputs.result }} diff --git a/.github/workflows/remove-unused-labels.yml b/.github/workflows/remove-unused-labels.yml new file mode 100644 index 000000000..a2259d718 --- /dev/null +++ b/.github/workflows/remove-unused-labels.yml @@ -0,0 +1,75 @@ +name: Remove Unused Labels +on: + workflow_dispatch: + +jobs: + cleanup: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + contents: read + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Fetch All Issues and PRs + id: fetch_issues_prs + uses: actions/github-script@v7.0.1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const issues = await github.paginate(github.rest.issues.listForRepo, { + owner: context.repo.owner, + repo: context.repo.repo, + state: 'all', + per_page: 100 + }); + + const labelsInUse = new Set(); + issues.forEach(issue => { + issue.labels.forEach(label => { + labelsInUse.add(label.name); + }); + }); + + return JSON.stringify(Array.from(labelsInUse)); + result-encoding: string + + - name: Fetch All Labels + id: fetch_labels + uses: actions/github-script@v7.0.1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const labels = await github.paginate(github.rest.issues.listLabelsForRepo, { + owner: context.repo.owner, + repo: context.repo.repo, + per_page: 100 + }); + + return JSON.stringify(labels.map(label => label.name)); + result-encoding: string + + - name: Remove Unused Labels + uses: actions/github-script@v7.0.1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const labelsInUse = new Set(JSON.parse(process.env.LABELS_IN_USE)); + const allLabels = JSON.parse(process.env.ALL_LABELS); + + const unusedLabels = allLabels.filter(label => !labelsInUse.has(label)); + + for (const label of unusedLabels) { + await github.rest.issues.deleteLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + name: label + }); + console.log(`Deleted label: ${label}`); + } + + env: + LABELS_IN_USE: ${{ steps.fetch_issues_prs.outputs.result }} + ALL_LABELS: ${{ steps.fetch_labels.outputs.result }} \ No newline at end of file diff --git a/.github/workflows/update-version-file-on-release.yml b/.github/workflows/update-version-file-on-release.yml index f582edf48..dc29d770b 100644 --- a/.github/workflows/update-version-file-on-release.yml +++ b/.github/workflows/update-version-file-on-release.yml @@ -8,7 +8,7 @@ jobs: update-version: runs-on: ubuntu-latest env: - TAG_VERSION: ${{ github.event.release.tag_name }} + TAG_VERSION: ${{ github.event.release.tag_name }} steps: # Step 1: Checkout the original repository's code - name: Checkout code @@ -26,33 +26,33 @@ jobs: - name: Check and delete existing tag run: | if git rev-parse ${{ env.TAG_VERSION }} >/dev/null 2>&1; then - git tag -d ${{ env.TAG_VERSION }} - git push --delete origin ${{ env.TAG_VERSION }} + git tag -d ${{ env.TAG_VERSION }} # Delete local tag + git push --delete origin ${{ env.TAG_VERSION }} # Delete remote tag fi # Step 4: Update version file - name: Update version file run: | - echo "${{ env.TAG_VERSION }}" > version/version + echo "${{ env.TAG_VERSION }}" > version/version # Write the version to the file - # Step 5: Commit and push changes + # Step 5: Commit and push changes to the correct branch - name: Commit and push changes env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | git add version/version git commit -m "Update version to ${{ env.TAG_VERSION }}" - git push origin HEAD:${{ github.ref }} + git push origin HEAD:${{ github.ref }} # Push to the current branch - # Step 6: Create and push tag + # Step 6: Create and push new tag - name: Create and push tag env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - git tag ${{ env.TAG_VERSION }} - git push origin ${{ env.TAG_VERSION }} + git tag ${{ env.TAG_VERSION }} # Create new tag + git push origin ${{ env.TAG_VERSION }} # Push the tag - # Step 8: Find and Publish Draft Release + # Step 7: Find and Publish Draft Release - name: Find and Publish Draft Release uses: actions/github-script@v6 with: From 0849ee44ac57a3e01fcf1f4920ee4e5eb62cd5f0 Mon Sep 17 00:00:00 2001 From: chao <48119764+withchao@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:15:51 +0800 Subject: [PATCH 16/36] fix: too many tokens (#612) --- internal/api/admin/admin.go | 20 + internal/api/admin/start.go | 7 + internal/api/chat/chat.go | 8 + internal/api/chat/start.go | 4 + internal/rpc/admin/application.go | 128 ++ pkg/common/db/database/admin.go | 35 +- pkg/common/db/model/admin/application.go | 83 + pkg/common/db/table/admin/application.go | 29 + pkg/protocol/admin/admin.pb.go | 2143 +++++++++++++++++----- pkg/protocol/admin/admin.proto | 76 + 10 files changed, 2033 insertions(+), 500 deletions(-) create mode 100644 internal/rpc/admin/application.go create mode 100644 pkg/common/db/model/admin/application.go create mode 100644 pkg/common/db/table/admin/application.go diff --git a/internal/api/admin/admin.go b/internal/api/admin/admin.go index df0d8531e..e4f34b906 100644 --- a/internal/api/admin/admin.go +++ b/internal/api/admin/admin.go @@ -566,3 +566,23 @@ func (o *Api) SetAllowRegister(c *gin.Context) { func (o *Api) GetAllowRegister(c *gin.Context) { a2r.Call(chat.ChatClient.GetAllowRegister, o.chatClient, c) } + +func (o *Api) LatestApplicationVersion(c *gin.Context) { + a2r.Call(admin.AdminClient.LatestApplicationVersion, o.adminClient, c) +} + +func (o *Api) PageApplicationVersion(c *gin.Context) { + a2r.Call(admin.AdminClient.PageApplicationVersion, o.adminClient, c) +} + +func (o *Api) AddApplicationVersion(c *gin.Context) { + a2r.Call(admin.AdminClient.AddApplicationVersion, o.adminClient, c) +} + +func (o *Api) UpdateApplicationVersion(c *gin.Context) { + a2r.Call(admin.AdminClient.UpdateApplicationVersion, o.adminClient, c) +} + +func (o *Api) DeleteApplicationVersion(c *gin.Context) { + a2r.Call(admin.AdminClient.DeleteApplicationVersion, o.adminClient, c) +} diff --git a/internal/api/admin/start.go b/internal/api/admin/start.go index fc53c94f8..3aa1e717d 100644 --- a/internal/api/admin/start.go +++ b/internal/api/admin/start.go @@ -135,4 +135,11 @@ func SetAdminRoute(router gin.IRouter, admin *Api, mw *chatmw.MW) { statistic := router.Group("/statistic", mw.CheckAdmin) statistic.POST("/new_user_count", admin.NewUserCount) statistic.POST("/login_user_count", admin.LoginUserCount) + + applicationGroup := router.Group("application") + applicationGroup.POST("/add_version", mw.CheckAdmin, admin.AddApplicationVersion) + applicationGroup.POST("/update_version", mw.CheckAdmin, admin.UpdateApplicationVersion) + applicationGroup.POST("/delete_version", mw.CheckAdmin, admin.DeleteApplicationVersion) + applicationGroup.POST("/latest_version", admin.LatestApplicationVersion) + applicationGroup.POST("/page_versions", admin.PageApplicationVersion) } diff --git a/internal/api/chat/chat.go b/internal/api/chat/chat.go index eca5e3bbe..d6d8d51e1 100644 --- a/internal/api/chat/chat.go +++ b/internal/api/chat/chat.go @@ -360,3 +360,11 @@ func (o *Api) SearchFriend(c *gin.Context) { } apiresp.GinSuccess(c, resp) } + +func (o *Api) LatestApplicationVersion(c *gin.Context) { + a2r.Call(admin.AdminClient.LatestApplicationVersion, o.adminClient, c) +} + +func (o *Api) PageApplicationVersion(c *gin.Context) { + a2r.Call(admin.AdminClient.PageApplicationVersion, o.adminClient, c) +} diff --git a/internal/api/chat/start.go b/internal/api/chat/start.go index 22cb38bf1..81b250cd1 100644 --- a/internal/api/chat/start.go +++ b/internal/api/chat/start.go @@ -86,5 +86,9 @@ func SetChatRoute(router gin.IRouter, chat *Api, mw *chatmw.MW) { router.Group("/client_config").POST("/get", chat.GetClientConfig) // Get client initialization configuration + applicationGroup := router.Group("application") + applicationGroup.POST("/latest_version", chat.LatestApplicationVersion) + applicationGroup.POST("/page_versions", chat.PageApplicationVersion) + router.Group("/callback").POST("/open_im", chat.OpenIMCallback) // Callback } diff --git a/internal/rpc/admin/application.go b/internal/rpc/admin/application.go new file mode 100644 index 000000000..6aff546de --- /dev/null +++ b/internal/rpc/admin/application.go @@ -0,0 +1,128 @@ +package admin + +import ( + "context" + admindb "github.com/openimsdk/chat/pkg/common/db/table/admin" + "github.com/openimsdk/chat/pkg/common/mctx" + "github.com/openimsdk/chat/pkg/protocol/admin" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/utils/datautil" + "github.com/redis/go-redis/v9" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "time" +) + +func IsNotFound(err error) bool { + switch errs.Unwrap(err) { + case redis.Nil, mongo.ErrNoDocuments: + return true + default: + return false + } +} + +func (o *adminServer) db2pbApplication(val *admindb.Application) *admin.ApplicationVersion { + return &admin.ApplicationVersion{ + Id: val.ID.Hex(), + Platform: val.Platform, + Version: val.Version, + Url: val.Url, + Text: val.Text, + Force: val.Force, + Latest: val.Latest, + Hot: val.Hot, + CreateTime: val.CreateTime.UnixMilli(), + } +} + +func (o *adminServer) LatestApplicationVersion(ctx context.Context, req *admin.LatestApplicationVersionReq) (*admin.LatestApplicationVersionResp, error) { + res, err := o.Database.LatestVersion(ctx, req.Platform) + if err == nil { + return &admin.LatestApplicationVersionResp{Version: o.db2pbApplication(res)}, nil + } else if IsNotFound(err) { + return &admin.LatestApplicationVersionResp{}, nil + } else { + return nil, err + } +} + +func (o *adminServer) AddApplicationVersion(ctx context.Context, req *admin.AddApplicationVersionReq) (*admin.AddApplicationVersionResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + val := &admindb.Application{ + ID: primitive.NewObjectID(), + Platform: req.Platform, + Version: req.Version, + Url: req.Url, + Text: req.Text, + Force: req.Force, + Latest: req.Latest, + Hot: req.Hot, + CreateTime: time.Now(), + } + if err := o.Database.AddVersion(ctx, val); err != nil { + return nil, err + } + return &admin.AddApplicationVersionResp{}, nil +} + +func (o *adminServer) UpdateApplicationVersion(ctx context.Context, req *admin.UpdateApplicationVersionReq) (*admin.UpdateApplicationVersionResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + oid, err := primitive.ObjectIDFromHex(req.Id) + if err != nil { + return nil, errs.ErrArgs.WrapMsg("invalid id " + err.Error()) + } + update := make(map[string]any) + putUpdate(update, "platform", req.Platform) + putUpdate(update, "version", req.Version) + putUpdate(update, "url", req.Url) + putUpdate(update, "text", req.Text) + putUpdate(update, "force", req.Force) + putUpdate(update, "latest", req.Latest) + putUpdate(update, "hot", req.Hot) + if err := o.Database.UpdateVersion(ctx, oid, update); err != nil { + return nil, err + } + return &admin.UpdateApplicationVersionResp{}, nil +} + +func (o *adminServer) DeleteApplicationVersion(ctx context.Context, req *admin.DeleteApplicationVersionReq) (*admin.DeleteApplicationVersionResp, error) { + if _, err := mctx.CheckAdmin(ctx); err != nil { + return nil, err + } + ids := make([]primitive.ObjectID, 0, len(req.Id)) + for _, id := range req.Id { + oid, err := primitive.ObjectIDFromHex(id) + if err != nil { + return nil, errs.ErrArgs.WrapMsg("invalid id " + err.Error()) + } + ids = append(ids, oid) + } + if err := o.Database.DeleteVersion(ctx, ids); err != nil { + return nil, err + } + return &admin.DeleteApplicationVersionResp{}, nil +} + +func (o *adminServer) PageApplicationVersion(ctx context.Context, req *admin.PageApplicationVersionReq) (*admin.PageApplicationVersionResp, error) { + total, res, err := o.Database.PageVersion(ctx, req.Platform, req.Pagination) + if err != nil { + return nil, err + } + return &admin.PageApplicationVersionResp{ + Total: total, + Versions: datautil.Slice(res, o.db2pbApplication), + }, nil +} + +func putUpdate[T any](update map[string]any, name string, val interface{ GetValuePtr() *T }) { + ptrVal := val.GetValuePtr() + if ptrVal == nil { + return + } + update[name] = *ptrVal +} diff --git a/pkg/common/db/database/admin.go b/pkg/common/db/database/admin.go index bf4859772..527a32d65 100644 --- a/pkg/common/db/database/admin.go +++ b/pkg/common/db/database/admin.go @@ -16,7 +16,7 @@ package database import ( "context" - "github.com/openimsdk/chat/pkg/common/tokenverify" + "go.mongodb.org/mongo-driver/bson/primitive" "time" "github.com/openimsdk/chat/pkg/common/db/cache" @@ -78,6 +78,11 @@ type AdminDatabaseInterface interface { CacheToken(ctx context.Context, userID string, token string, expire time.Duration) error GetTokens(ctx context.Context, userID string) (map[string]int32, error) DeleteToken(ctx context.Context, userID string) error + LatestVersion(ctx context.Context, platform string) (*admindb.Application, error) + AddVersion(ctx context.Context, val *admindb.Application) error + UpdateVersion(ctx context.Context, id primitive.ObjectID, update map[string]any) error + DeleteVersion(ctx context.Context, id []primitive.ObjectID) error + PageVersion(ctx context.Context, platforms []string, page pagination.Pagination) (int64, []*admindb.Application, error) } func NewAdminDatabase(cli *mongoutil.Client, rdb redis.UniversalClient, token *tokenverify.Token) (AdminDatabaseInterface, error) { @@ -117,6 +122,10 @@ func NewAdminDatabase(cli *mongoutil.Client, rdb redis.UniversalClient, token *t if err != nil { return nil, err } + application, err := admin.NewApplication(cli.GetDB()) + if err != nil { + return nil, err + } return &AdminDatabase{ tx: cli.GetTx(), admin: a, @@ -128,7 +137,8 @@ func NewAdminDatabase(cli *mongoutil.Client, rdb redis.UniversalClient, token *t registerAddGroup: registerAddGroup, applet: applet, clientConfig: clientConfig, - cache: cache.NewTokenInterface(rdb, token), + application: application, + cache: cache.NewTokenInterface(rdb), }, nil } @@ -143,6 +153,7 @@ type AdminDatabase struct { registerAddGroup admindb.RegisterAddGroupInterface applet admindb.AppletInterface clientConfig admindb.ClientConfigInterface + application admindb.ApplicationInterface cache cache.TokenInterface } @@ -337,3 +348,23 @@ func (o *AdminDatabase) GetTokens(ctx context.Context, userID string) (map[strin func (o *AdminDatabase) DeleteToken(ctx context.Context, userID string) error { return o.cache.DeleteTokenByUid(ctx, userID) } + +func (o *AdminDatabase) LatestVersion(ctx context.Context, platform string) (*admindb.Application, error) { + return o.application.LatestVersion(ctx, platform) +} + +func (o *AdminDatabase) AddVersion(ctx context.Context, val *admindb.Application) error { + return o.application.AddVersion(ctx, val) +} + +func (o *AdminDatabase) UpdateVersion(ctx context.Context, id primitive.ObjectID, update map[string]any) error { + return o.application.UpdateVersion(ctx, id, update) +} + +func (o *AdminDatabase) DeleteVersion(ctx context.Context, id []primitive.ObjectID) error { + return o.application.DeleteVersion(ctx, id) +} + +func (o *AdminDatabase) PageVersion(ctx context.Context, platforms []string, page pagination.Pagination) (int64, []*admindb.Application, error) { + return o.application.PageVersion(ctx, platforms, page) +} diff --git a/pkg/common/db/model/admin/application.go b/pkg/common/db/model/admin/application.go new file mode 100644 index 000000000..e69268d21 --- /dev/null +++ b/pkg/common/db/model/admin/application.go @@ -0,0 +1,83 @@ +package admin + +import ( + "context" + "github.com/openimsdk/chat/pkg/common/db/table/admin" + admindb "github.com/openimsdk/chat/pkg/common/db/table/admin" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +func NewApplication(db *mongo.Database) (admindb.ApplicationInterface, error) { + coll := db.Collection("application") + _, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{ + { + Keys: bson.D{ + {Key: "platform", Value: 1}, + {Key: "version", Value: 1}, + }, + Options: options.Index().SetUnique(true), + }, + { + Keys: bson.D{ + {Key: "latest", Value: -1}, + }, + }, + }) + if err != nil { + return nil, err + } + return &ApplicationMgo{coll: coll}, nil +} + +type ApplicationMgo struct { + coll *mongo.Collection +} + +func (a *ApplicationMgo) sort() any { + return bson.D{{"latest", -1}, {"_id", -1}} +} + +func (a *ApplicationMgo) LatestVersion(ctx context.Context, platform string) (*admin.Application, error) { + return mongoutil.FindOne[*admin.Application](ctx, a.coll, bson.M{"platform": platform}, options.FindOne().SetSort(a.sort())) +} + +func (a *ApplicationMgo) AddVersion(ctx context.Context, val *admin.Application) error { + if val.ID.IsZero() { + val.ID = primitive.NewObjectID() + } + return mongoutil.InsertMany(ctx, a.coll, []*admin.Application{val}) +} + +func (a *ApplicationMgo) UpdateVersion(ctx context.Context, id primitive.ObjectID, update map[string]any) error { + if len(update) == 0 { + return nil + } + return mongoutil.UpdateOne(ctx, a.coll, bson.M{"_id": id}, bson.M{"$set": update}, true) +} + +func (a *ApplicationMgo) DeleteVersion(ctx context.Context, id []primitive.ObjectID) error { + if len(id) == 0 { + return nil + } + return mongoutil.DeleteMany(ctx, a.coll, bson.M{"_id": bson.M{"$in": id}}) +} + +func (a *ApplicationMgo) PageVersion(ctx context.Context, platforms []string, page pagination.Pagination) (int64, []*admin.Application, error) { + filter := bson.M{} + if len(platforms) > 0 { + filter["platform"] = bson.M{"$in": platforms} + } + return mongoutil.FindPage[*admin.Application](ctx, a.coll, filter, page, options.Find().SetSort(a.sort())) +} + +func (a *ApplicationMgo) FindPlatform(ctx context.Context, id []primitive.ObjectID) ([]string, error) { + if len(id) == 0 { + return nil, nil + } + return mongoutil.Find[string](ctx, a.coll, bson.M{"_id": bson.M{"$in": id}}, options.Find().SetProjection(bson.M{"_id": 0, "platform": 1})) +} diff --git a/pkg/common/db/table/admin/application.go b/pkg/common/db/table/admin/application.go new file mode 100644 index 000000000..44333fa3a --- /dev/null +++ b/pkg/common/db/table/admin/application.go @@ -0,0 +1,29 @@ +package admin + +import ( + "context" + "github.com/openimsdk/tools/db/pagination" + "go.mongodb.org/mongo-driver/bson/primitive" + "time" +) + +type Application struct { + ID primitive.ObjectID `bson:"_id"` + Platform string `bson:"platform"` + Hot bool `bson:"hot"` + Version string `bson:"version"` + Url string `bson:"url"` + Text string `bson:"text"` + Force bool `bson:"force"` + Latest bool `bson:"latest"` + CreateTime time.Time `bson:"create_time"` +} + +type ApplicationInterface interface { + LatestVersion(ctx context.Context, platform string) (*Application, error) + AddVersion(ctx context.Context, val *Application) error + UpdateVersion(ctx context.Context, id primitive.ObjectID, update map[string]any) error + DeleteVersion(ctx context.Context, id []primitive.ObjectID) error + PageVersion(ctx context.Context, platforms []string, page pagination.Pagination) (int64, []*Application, error) + FindPlatform(ctx context.Context, id []primitive.ObjectID) ([]string, error) +} diff --git a/pkg/protocol/admin/admin.pb.go b/pkg/protocol/admin/admin.pb.go index 9b8161e14..309326fbe 100644 --- a/pkg/protocol/admin/admin.pb.go +++ b/pkg/protocol/admin/admin.pb.go @@ -15,7 +15,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.33.0 -// protoc v5.27.1 +// protoc v5.26.0 // source: admin/admin.proto package admin @@ -5398,6 +5398,688 @@ func (x *GetUserTokenResp) GetTokensMap() map[string]int32 { return nil } +type ApplicationVersion struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` + Platform string `protobuf:"bytes,2,opt,name=platform,proto3" json:"platform"` + Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version"` + Url string `protobuf:"bytes,4,opt,name=url,proto3" json:"url"` + Text string `protobuf:"bytes,5,opt,name=text,proto3" json:"text"` + Force bool `protobuf:"varint,6,opt,name=force,proto3" json:"force"` + Latest bool `protobuf:"varint,7,opt,name=latest,proto3" json:"latest"` + Hot bool `protobuf:"varint,8,opt,name=hot,proto3" json:"hot"` + CreateTime int64 `protobuf:"varint,9,opt,name=createTime,proto3" json:"createTime"` +} + +func (x *ApplicationVersion) Reset() { + *x = ApplicationVersion{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[103] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ApplicationVersion) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ApplicationVersion) ProtoMessage() {} + +func (x *ApplicationVersion) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[103] + 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 ApplicationVersion.ProtoReflect.Descriptor instead. +func (*ApplicationVersion) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{103} +} + +func (x *ApplicationVersion) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *ApplicationVersion) GetPlatform() string { + if x != nil { + return x.Platform + } + return "" +} + +func (x *ApplicationVersion) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *ApplicationVersion) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *ApplicationVersion) GetText() string { + if x != nil { + return x.Text + } + return "" +} + +func (x *ApplicationVersion) GetForce() bool { + if x != nil { + return x.Force + } + return false +} + +func (x *ApplicationVersion) GetLatest() bool { + if x != nil { + return x.Latest + } + return false +} + +func (x *ApplicationVersion) GetHot() bool { + if x != nil { + return x.Hot + } + return false +} + +func (x *ApplicationVersion) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +type LatestApplicationVersionReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Platform string `protobuf:"bytes,2,opt,name=platform,proto3" json:"platform"` + Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version"` +} + +func (x *LatestApplicationVersionReq) Reset() { + *x = LatestApplicationVersionReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[104] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LatestApplicationVersionReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LatestApplicationVersionReq) ProtoMessage() {} + +func (x *LatestApplicationVersionReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[104] + 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 LatestApplicationVersionReq.ProtoReflect.Descriptor instead. +func (*LatestApplicationVersionReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{104} +} + +func (x *LatestApplicationVersionReq) GetPlatform() string { + if x != nil { + return x.Platform + } + return "" +} + +func (x *LatestApplicationVersionReq) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +type LatestApplicationVersionResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Version *ApplicationVersion `protobuf:"bytes,1,opt,name=version,proto3" json:"version"` +} + +func (x *LatestApplicationVersionResp) Reset() { + *x = LatestApplicationVersionResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[105] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LatestApplicationVersionResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LatestApplicationVersionResp) ProtoMessage() {} + +func (x *LatestApplicationVersionResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[105] + 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 LatestApplicationVersionResp.ProtoReflect.Descriptor instead. +func (*LatestApplicationVersionResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{105} +} + +func (x *LatestApplicationVersionResp) GetVersion() *ApplicationVersion { + if x != nil { + return x.Version + } + return nil +} + +type AddApplicationVersionReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Platform string `protobuf:"bytes,1,opt,name=platform,proto3" json:"platform"` + Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version"` + Url string `protobuf:"bytes,3,opt,name=url,proto3" json:"url"` + Text string `protobuf:"bytes,4,opt,name=text,proto3" json:"text"` + Force bool `protobuf:"varint,5,opt,name=force,proto3" json:"force"` + Latest bool `protobuf:"varint,6,opt,name=latest,proto3" json:"latest"` + Hot bool `protobuf:"varint,7,opt,name=hot,proto3" json:"hot"` +} + +func (x *AddApplicationVersionReq) Reset() { + *x = AddApplicationVersionReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[106] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddApplicationVersionReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddApplicationVersionReq) ProtoMessage() {} + +func (x *AddApplicationVersionReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[106] + 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 AddApplicationVersionReq.ProtoReflect.Descriptor instead. +func (*AddApplicationVersionReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{106} +} + +func (x *AddApplicationVersionReq) GetPlatform() string { + if x != nil { + return x.Platform + } + return "" +} + +func (x *AddApplicationVersionReq) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *AddApplicationVersionReq) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *AddApplicationVersionReq) GetText() string { + if x != nil { + return x.Text + } + return "" +} + +func (x *AddApplicationVersionReq) GetForce() bool { + if x != nil { + return x.Force + } + return false +} + +func (x *AddApplicationVersionReq) GetLatest() bool { + if x != nil { + return x.Latest + } + return false +} + +func (x *AddApplicationVersionReq) GetHot() bool { + if x != nil { + return x.Hot + } + return false +} + +type AddApplicationVersionResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *AddApplicationVersionResp) Reset() { + *x = AddApplicationVersionResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[107] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddApplicationVersionResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddApplicationVersionResp) ProtoMessage() {} + +func (x *AddApplicationVersionResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[107] + 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 AddApplicationVersionResp.ProtoReflect.Descriptor instead. +func (*AddApplicationVersionResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{107} +} + +type UpdateApplicationVersionReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id"` + Platform *wrapperspb.StringValue `protobuf:"bytes,2,opt,name=platform,proto3" json:"platform"` + Version *wrapperspb.StringValue `protobuf:"bytes,3,opt,name=version,proto3" json:"version"` + Url *wrapperspb.StringValue `protobuf:"bytes,4,opt,name=url,proto3" json:"url"` + Text *wrapperspb.StringValue `protobuf:"bytes,5,opt,name=text,proto3" json:"text"` + Force *wrapperspb.BoolValue `protobuf:"bytes,6,opt,name=force,proto3" json:"force"` + Latest *wrapperspb.BoolValue `protobuf:"bytes,7,opt,name=latest,proto3" json:"latest"` + Hot *wrapperspb.BoolValue `protobuf:"bytes,8,opt,name=hot,proto3" json:"hot"` +} + +func (x *UpdateApplicationVersionReq) Reset() { + *x = UpdateApplicationVersionReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[108] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateApplicationVersionReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateApplicationVersionReq) ProtoMessage() {} + +func (x *UpdateApplicationVersionReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[108] + 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 UpdateApplicationVersionReq.ProtoReflect.Descriptor instead. +func (*UpdateApplicationVersionReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{108} +} + +func (x *UpdateApplicationVersionReq) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *UpdateApplicationVersionReq) GetPlatform() *wrapperspb.StringValue { + if x != nil { + return x.Platform + } + return nil +} + +func (x *UpdateApplicationVersionReq) GetVersion() *wrapperspb.StringValue { + if x != nil { + return x.Version + } + return nil +} + +func (x *UpdateApplicationVersionReq) GetUrl() *wrapperspb.StringValue { + if x != nil { + return x.Url + } + return nil +} + +func (x *UpdateApplicationVersionReq) GetText() *wrapperspb.StringValue { + if x != nil { + return x.Text + } + return nil +} + +func (x *UpdateApplicationVersionReq) GetForce() *wrapperspb.BoolValue { + if x != nil { + return x.Force + } + return nil +} + +func (x *UpdateApplicationVersionReq) GetLatest() *wrapperspb.BoolValue { + if x != nil { + return x.Latest + } + return nil +} + +func (x *UpdateApplicationVersionReq) GetHot() *wrapperspb.BoolValue { + if x != nil { + return x.Hot + } + return nil +} + +type UpdateApplicationVersionResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UpdateApplicationVersionResp) Reset() { + *x = UpdateApplicationVersionResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[109] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateApplicationVersionResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateApplicationVersionResp) ProtoMessage() {} + +func (x *UpdateApplicationVersionResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[109] + 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 UpdateApplicationVersionResp.ProtoReflect.Descriptor instead. +func (*UpdateApplicationVersionResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{109} +} + +type DeleteApplicationVersionReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id []string `protobuf:"bytes,1,rep,name=id,proto3" json:"id"` +} + +func (x *DeleteApplicationVersionReq) Reset() { + *x = DeleteApplicationVersionReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[110] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteApplicationVersionReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteApplicationVersionReq) ProtoMessage() {} + +func (x *DeleteApplicationVersionReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[110] + 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 DeleteApplicationVersionReq.ProtoReflect.Descriptor instead. +func (*DeleteApplicationVersionReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{110} +} + +func (x *DeleteApplicationVersionReq) GetId() []string { + if x != nil { + return x.Id + } + return nil +} + +type DeleteApplicationVersionResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DeleteApplicationVersionResp) Reset() { + *x = DeleteApplicationVersionResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[111] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteApplicationVersionResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteApplicationVersionResp) ProtoMessage() {} + +func (x *DeleteApplicationVersionResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[111] + 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 DeleteApplicationVersionResp.ProtoReflect.Descriptor instead. +func (*DeleteApplicationVersionResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{111} +} + +type PageApplicationVersionReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Platform []string `protobuf:"bytes,1,rep,name=platform,proto3" json:"platform"` + Pagination *sdkws.RequestPagination `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination"` +} + +func (x *PageApplicationVersionReq) Reset() { + *x = PageApplicationVersionReq{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[112] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PageApplicationVersionReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PageApplicationVersionReq) ProtoMessage() {} + +func (x *PageApplicationVersionReq) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[112] + 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 PageApplicationVersionReq.ProtoReflect.Descriptor instead. +func (*PageApplicationVersionReq) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{112} +} + +func (x *PageApplicationVersionReq) GetPlatform() []string { + if x != nil { + return x.Platform + } + return nil +} + +func (x *PageApplicationVersionReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +type PageApplicationVersionResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Total int64 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` + Versions []*ApplicationVersion `protobuf:"bytes,2,rep,name=versions,proto3" json:"versions"` +} + +func (x *PageApplicationVersionResp) Reset() { + *x = PageApplicationVersionResp{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_admin_proto_msgTypes[113] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PageApplicationVersionResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PageApplicationVersionResp) ProtoMessage() {} + +func (x *PageApplicationVersionResp) ProtoReflect() protoreflect.Message { + mi := &file_admin_admin_proto_msgTypes[113] + 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 PageApplicationVersionResp.ProtoReflect.Descriptor instead. +func (*PageApplicationVersionResp) Descriptor() ([]byte, []int) { + return file_admin_admin_proto_rawDescGZIP(), []int{113} +} + +func (x *PageApplicationVersionResp) GetTotal() int64 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *PageApplicationVersionResp) GetVersions() []*ApplicationVersion { + if x != nil { + return x.Versions + } + return nil +} + var File_admin_admin_proto protoreflect.FileDescriptor var file_admin_admin_proto_rawDesc = []byte{ @@ -5925,270 +6607,391 @@ var file_admin_admin_proto_rawDesc = []byte{ 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, 0x05, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, - 0x01, 0x32, 0xbe, 0x20, 0x0a, 0x05, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x12, 0x38, 0x0a, 0x05, 0x4c, - 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x16, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x6f, - 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x4c, 0x6f, 0x67, 0x69, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x53, 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, - 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, - 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, - 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, - 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, - 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x41, 0x64, - 0x6d, 0x69, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20, 0x2e, - 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x6d, - 0x69, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, - 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, - 0x64, 0x6d, 0x69, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, - 0x73, 0x70, 0x12, 0x4d, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x49, 0x6e, - 0x66, 0x6f, 0x12, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, - 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, - 0x71, 0x1a, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, - 0x2e, 0x47, 0x65, 0x74, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, - 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x41, 0x64, 0x64, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, - 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x62, 0x0a, 0x13, 0x43, 0x68, 0x61, + 0x01, 0x22, 0xe0, 0x01, 0x0a, 0x12, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, + 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, + 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x10, + 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, + 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x74, 0x65, 0x78, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x61, + 0x74, 0x65, 0x73, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x6c, 0x61, 0x74, 0x65, + 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x68, 0x6f, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x03, 0x68, 0x6f, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, + 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x54, 0x69, 0x6d, 0x65, 0x22, 0x53, 0x0a, 0x1b, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x41, 0x70, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, + 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x5a, 0x0a, 0x1c, 0x4c, 0x61, 0x74, + 0x65, 0x73, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x3a, 0x0a, 0x07, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xb6, 0x01, 0x0a, 0x18, 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x71, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x18, + 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, + 0x78, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, 0x14, + 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, + 0x6f, 0x72, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, + 0x68, 0x6f, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x68, 0x6f, 0x74, 0x22, 0x1b, + 0x0a, 0x19, 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x22, 0x95, 0x03, 0x0a, 0x1b, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x38, 0x0a, 0x08, 0x70, + 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x70, 0x6c, 0x61, + 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x36, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, + 0x03, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, + 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x30, 0x0a, + 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, + 0x30, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, + 0x65, 0x12, 0x32, 0x0a, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x6c, + 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x03, 0x68, 0x6f, 0x74, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x03, + 0x68, 0x6f, 0x74, 0x22, 0x1e, 0x0a, 0x1c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x22, 0x2d, 0x0a, 0x1b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x02, + 0x69, 0x64, 0x22, 0x1e, 0x0a, 0x1c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x22, 0x78, 0x0a, 0x19, 0x50, 0x61, 0x67, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x12, + 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x3f, 0x0a, 0x0a, 0x70, + 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x70, 0x0a, 0x1a, + 0x50, 0x61, 0x67, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, + 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, + 0x12, 0x3c, 0x0a, 0x08, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0xee, + 0x24, 0x0a, 0x05, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x12, 0x38, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, + 0x6e, 0x12, 0x16, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x53, 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, + 0x77, 0x6f, 0x72, 0x64, 0x12, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, + 0x72, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, + 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x41, 0x64, 0x6d, 0x69, 0x6e, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x6d, 0x69, + 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x4d, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, + 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, + 0x65, 0x74, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x1e, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, + 0x74, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, + 0x0a, 0x0f, 0x41, 0x64, 0x64, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x41, 0x64, 0x64, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x62, 0x0a, 0x13, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x24, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, - 0x12, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, - 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, - 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x64, 0x6d, 0x69, - 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, - 0x0f, 0x44, 0x65, 0x6c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, - 0x44, 0x65, 0x6c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, - 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, - 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5f, 0x0a, 0x12, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, - 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x23, 0x2e, 0x6f, 0x70, - 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, - 0x68, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, - 0x1a, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, - 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x59, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, - 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x12, 0x21, 0x2e, 0x6f, 0x70, 0x65, + 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x61, + 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x44, 0x65, + 0x6c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x20, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, + 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, + 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, + 0x65, 0x6c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x5f, 0x0a, 0x12, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x64, 0x6d, 0x69, + 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x64, + 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x24, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, + 0x72, 0x63, 0x68, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x12, 0x59, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x12, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, - 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x22, 0x2e, - 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, - 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, - 0x70, 0x12, 0x59, 0x0a, 0x10, 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, - 0x72, 0x69, 0x65, 0x6e, 0x64, 0x12, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x59, + 0x0a, 0x10, 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, + 0x6e, 0x64, 0x12, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, + 0x6e, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, - 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, - 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, - 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, - 0x46, 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, - 0x64, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, - 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, - 0x6e, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, - 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, - 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x62, 0x0a, 0x13, 0x53, 0x65, + 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, 0x46, 0x69, 0x6e, + 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x12, 0x22, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, + 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, + 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, + 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x62, 0x0a, 0x13, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x12, 0x24, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, - 0x64, 0x12, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, - 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, - 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, - 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x65, 0x66, - 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, - 0x0a, 0x0f, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, - 0x70, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, - 0x2e, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, - 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, - 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, - 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, - 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, - 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, - 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, - 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x44, 0x65, - 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x59, - 0x0a, 0x10, 0x46, 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, - 0x75, 0x70, 0x12, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, - 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, - 0x75, 0x70, 0x52, 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, - 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5f, 0x0a, 0x12, 0x53, 0x65, 0x61, - 0x72, 0x63, 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, - 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, - 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, - 0x70, 0x52, 0x65, 0x71, 0x1a, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, + 0x64, 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, - 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, 0x41, 0x64, - 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, - 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, - 0x64, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, - 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, - 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, 0x47, 0x65, 0x6e, 0x49, - 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x22, 0x2e, - 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x6e, - 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, - 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, - 0x2e, 0x47, 0x65, 0x6e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, - 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5f, 0x0a, 0x12, 0x46, 0x69, 0x6e, 0x64, 0x49, 0x6e, - 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x23, 0x2e, 0x6f, - 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, - 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, + 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x41, + 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x20, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, + 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, + 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, + 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, + 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x59, 0x0a, 0x10, 0x46, + 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, + 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, + 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, + 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5f, 0x0a, 0x12, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, + 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x23, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x1a, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, - 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, - 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, 0x55, 0x73, 0x65, 0x49, 0x6e, + 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x22, 0x2e, 0x6f, - 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x73, 0x65, 0x49, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, - 0x55, 0x73, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x49, 0x6e, 0x76, 0x69, + 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, 0x47, 0x65, 0x6e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, - 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x49, 0x6e, 0x76, + 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x6e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x23, - 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, - 0x6c, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x12, 0x65, 0x0a, 0x14, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x6e, 0x76, - 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x25, 0x2e, 0x6f, 0x70, - 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, - 0x68, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, - 0x65, 0x71, 0x1a, 0x26, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, - 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x6b, 0x0a, 0x16, 0x53, 0x65, - 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, - 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, - 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x28, 0x2e, - 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, - 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, - 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x62, 0x0a, 0x13, 0x41, 0x64, 0x64, 0x55, 0x73, - 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x24, - 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, - 0x64, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, - 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, - 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x62, 0x0a, 0x13, 0x44, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, + 0x6e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x12, 0x5f, 0x0a, 0x12, 0x46, 0x69, 0x6e, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x49, 0x6e, 0x76, + 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x24, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, + 0x6e, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, 0x55, 0x73, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x73, 0x65, 0x49, 0x6e, 0x76, 0x69, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x73, 0x65, + 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x49, 0x6e, + 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x65, 0x0a, 0x14, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x6e, + 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, + 0x26, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, + 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x6b, 0x0a, 0x16, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, + 0x6e, 0x12, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, + 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x28, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, + 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x62, 0x0a, 0x13, 0x41, 0x64, 0x64, 0x55, 0x73, 0x65, 0x72, 0x49, + 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x24, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x55, 0x73, + 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, + 0x71, 0x1a, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x41, 0x64, 0x64, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, + 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x62, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x55, + 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, + 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, - 0x69, 0x6e, 0x12, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, - 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, - 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, - 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x49, - 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, - 0x5c, 0x0a, 0x11, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, - 0x64, 0x64, 0x65, 0x6e, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, - 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, - 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x50, - 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x53, 0x0a, - 0x0e, 0x41, 0x64, 0x64, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x12, - 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, - 0x64, 0x64, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x71, - 0x1a, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, - 0x41, 0x64, 0x64, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x12, 0x53, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, - 0x64, 0x64, 0x65, 0x6e, 0x12, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, - 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, - 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, - 0x64, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x59, 0x0a, 0x10, 0x43, 0x61, 0x6e, 0x63, 0x65, - 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x12, 0x21, 0x2e, 0x6f, 0x70, - 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, - 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x22, - 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x61, - 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, - 0x73, 0x70, 0x12, 0x44, 0x0a, 0x09, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x12, - 0x1a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6f, 0x70, - 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4a, 0x0a, 0x0b, 0x55, 0x6e, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, - 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x6e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, - 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, - 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x6e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, - 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, - 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, - 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, - 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x66, - 0x6f, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, - 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, - 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, - 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x6b, 0x0a, 0x16, 0x43, 0x68, - 0x65, 0x63, 0x6b, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x46, 0x6f, 0x72, 0x62, 0x69, - 0x64, 0x64, 0x65, 0x6e, 0x12, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, - 0x72, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x28, 0x2e, - 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x65, - 0x63, 0x6b, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, - 0x64, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x62, 0x0a, 0x13, 0x43, 0x68, 0x65, 0x63, 0x6b, - 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x12, 0x24, - 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, - 0x65, 0x63, 0x6b, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, - 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x46, 0x6f, - 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4a, 0x0a, 0x0b, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1c, 0x2e, 0x6f, 0x70, 0x65, - 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, - 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x47, 0x0a, 0x0a, 0x50, 0x61, 0x72, 0x73, 0x65, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, - 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, - 0x65, 0x71, 0x1a, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, - 0x6e, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, - 0x12, 0x44, 0x0a, 0x09, 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x12, 0x1a, 0x2e, + 0x69, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, + 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, + 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, + 0x6e, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, + 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x50, 0x46, 0x6f, 0x72, + 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x53, 0x0a, 0x0e, 0x41, 0x64, + 0x64, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x12, 0x1f, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x49, + 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, - 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, - 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, 0x6c, - 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x44, 0x0a, 0x09, 0x44, 0x65, 0x6c, 0x41, 0x70, 0x70, - 0x6c, 0x65, 0x74, 0x12, 0x1a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, - 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x1a, - 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, - 0x65, 0x6c, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4d, 0x0a, 0x0c, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x12, 0x1d, 0x2e, 0x6f, - 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6f, 0x70, - 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x47, 0x0a, 0x0a, 0x46, - 0x69, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x12, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, - 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x70, 0x70, - 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x53, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, + 0x6e, 0x12, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x44, 0x65, 0x6c, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, + 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x59, 0x0a, 0x10, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x12, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, + 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x44, 0x0a, 0x09, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1a, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, + 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4a, 0x0a, 0x0b, 0x55, 0x6e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x55, 0x73, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x6e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, + 0x65, 0x71, 0x1a, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x55, 0x6e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, + 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x55, 0x73, 0x65, 0x72, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, + 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, 0x46, 0x69, 0x6e, + 0x64, 0x55, 0x73, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x22, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, + 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x6b, 0x0a, 0x16, 0x43, 0x68, 0x65, 0x63, 0x6b, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, + 0x6e, 0x12, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x46, 0x6f, + 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x28, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x62, 0x0a, 0x13, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4c, 0x6f, 0x67, + 0x69, 0x6e, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x12, 0x24, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, + 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, + 0x71, 0x1a, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x46, 0x6f, 0x72, 0x62, 0x69, + 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4a, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x47, 0x0a, 0x0a, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x12, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, + 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x50, + 0x61, 0x72, 0x73, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x44, 0x0a, + 0x09, 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x12, 0x1a, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, + 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x12, 0x44, 0x0a, 0x09, 0x44, 0x65, 0x6c, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, + 0x12, 0x1a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, + 0x44, 0x65, 0x6c, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x41, + 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4d, 0x0a, 0x0c, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x12, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, + 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, + 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x47, 0x0a, 0x0a, 0x46, 0x69, 0x6e, 0x64, + 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x12, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, - 0x52, 0x65, 0x73, 0x70, 0x12, 0x4d, 0x0a, 0x0c, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x70, - 0x70, 0x6c, 0x65, 0x74, 0x12, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, - 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, - 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, - 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, - 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x53, - 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, - 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, - 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, - 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, - 0x53, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, - 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x44, 0x65, 0x6c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, - 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, - 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x43, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4d, 0x0a, 0x0c, 0x47, - 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1d, 0x2e, 0x6f, 0x70, - 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, - 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6f, 0x70, 0x65, - 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, - 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x49, 0x6e, - 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x20, 0x2e, - 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x49, 0x6e, 0x76, - 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, - 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x49, - 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x73, 0x64, 0x6b, 0x2f, 0x63, 0x68, 0x61, 0x74, 0x2f, - 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x61, 0x64, 0x6d, - 0x69, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x52, 0x65, 0x71, 0x1a, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x12, 0x4d, 0x0a, 0x0c, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x70, 0x70, 0x6c, 0x65, + 0x74, 0x12, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, + 0x1a, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, + 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x56, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x53, 0x65, 0x74, 0x43, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x74, 0x43, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x74, + 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x56, 0x0a, 0x0f, 0x44, 0x65, 0x6c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4d, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x55, + 0x73, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x49, 0x6e, 0x76, 0x61, 0x6c, + 0x69, 0x64, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, + 0x64, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x49, 0x6e, 0x76, 0x61, + 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x71, 0x0a, 0x18, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x4c, 0x61, 0x74, 0x65, 0x73, + 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x2a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x41, 0x70, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x68, 0x0a, 0x15, 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x70, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x1a, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x71, 0x0a, 0x18, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x1a, 0x2a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x71, 0x0a, 0x18, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x2a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x6b, 0x0a, 0x16, 0x50, 0x61, 0x67, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x50, 0x61, 0x67, 0x65, + 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x28, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x42, + 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x73, 0x64, 0x6b, 0x2f, 0x63, 0x68, 0x61, 0x74, 0x2f, 0x70, 0x6b, 0x67, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -6203,266 +7006,298 @@ func file_admin_admin_proto_rawDescGZIP() []byte { return file_admin_admin_proto_rawDescData } -var file_admin_admin_proto_msgTypes = make([]protoimpl.MessageInfo, 106) +var file_admin_admin_proto_msgTypes = make([]protoimpl.MessageInfo, 117) var file_admin_admin_proto_goTypes = []interface{}{ - (*LoginReq)(nil), // 0: openim.admin.LoginReq - (*LoginResp)(nil), // 1: openim.admin.LoginResp - (*AddAdminAccountReq)(nil), // 2: openim.admin.AddAdminAccountReq - (*AddAdminAccountResp)(nil), // 3: openim.admin.AddAdminAccountResp - (*AdminUpdateInfoReq)(nil), // 4: openim.admin.AdminUpdateInfoReq - (*AdminUpdateInfoResp)(nil), // 5: openim.admin.AdminUpdateInfoResp - (*ChangePasswordReq)(nil), // 6: openim.admin.ChangePasswordReq - (*ChangePasswordResp)(nil), // 7: openim.admin.ChangePasswordResp - (*GetAdminInfoReq)(nil), // 8: openim.admin.GetAdminInfoReq - (*ChangeAdminPasswordReq)(nil), // 9: openim.admin.ChangeAdminPasswordReq - (*ChangeAdminPasswordResp)(nil), // 10: openim.admin.ChangeAdminPasswordResp - (*DelAdminAccountReq)(nil), // 11: openim.admin.DelAdminAccountReq - (*DelAdminAccountResp)(nil), // 12: openim.admin.DelAdminAccountResp - (*SearchAdminAccountReq)(nil), // 13: openim.admin.SearchAdminAccountReq - (*SearchAdminAccountResp)(nil), // 14: openim.admin.SearchAdminAccountResp - (*GetAdminInfoResp)(nil), // 15: openim.admin.GetAdminInfoResp - (*AddDefaultFriendReq)(nil), // 16: openim.admin.AddDefaultFriendReq - (*AddDefaultFriendResp)(nil), // 17: openim.admin.AddDefaultFriendResp - (*DelDefaultFriendReq)(nil), // 18: openim.admin.DelDefaultFriendReq - (*DelDefaultFriendResp)(nil), // 19: openim.admin.DelDefaultFriendResp - (*FindDefaultFriendReq)(nil), // 20: openim.admin.FindDefaultFriendReq - (*FindDefaultFriendResp)(nil), // 21: openim.admin.FindDefaultFriendResp - (*SearchDefaultFriendReq)(nil), // 22: openim.admin.SearchDefaultFriendReq - (*DefaultFriendAttribute)(nil), // 23: openim.admin.DefaultFriendAttribute - (*SearchDefaultFriendResp)(nil), // 24: openim.admin.SearchDefaultFriendResp - (*AddDefaultGroupReq)(nil), // 25: openim.admin.AddDefaultGroupReq - (*AddDefaultGroupResp)(nil), // 26: openim.admin.AddDefaultGroupResp - (*DelDefaultGroupReq)(nil), // 27: openim.admin.DelDefaultGroupReq - (*DelDefaultGroupResp)(nil), // 28: openim.admin.DelDefaultGroupResp - (*FindDefaultGroupReq)(nil), // 29: openim.admin.FindDefaultGroupReq - (*FindDefaultGroupResp)(nil), // 30: openim.admin.FindDefaultGroupResp - (*SearchDefaultGroupReq)(nil), // 31: openim.admin.SearchDefaultGroupReq - (*GroupAttribute)(nil), // 32: openim.admin.GroupAttribute - (*SearchDefaultGroupResp)(nil), // 33: openim.admin.SearchDefaultGroupResp - (*AddInvitationCodeReq)(nil), // 34: openim.admin.AddInvitationCodeReq - (*AddInvitationCodeResp)(nil), // 35: openim.admin.AddInvitationCodeResp - (*GenInvitationCodeReq)(nil), // 36: openim.admin.GenInvitationCodeReq - (*GenInvitationCodeResp)(nil), // 37: openim.admin.GenInvitationCodeResp - (*FindInvitationCodeReq)(nil), // 38: openim.admin.FindInvitationCodeReq - (*FindInvitationCodeResp)(nil), // 39: openim.admin.FindInvitationCodeResp - (*UseInvitationCodeReq)(nil), // 40: openim.admin.UseInvitationCodeReq - (*UseInvitationCodeResp)(nil), // 41: openim.admin.UseInvitationCodeResp - (*DelInvitationCodeReq)(nil), // 42: openim.admin.DelInvitationCodeReq - (*DelInvitationCodeResp)(nil), // 43: openim.admin.DelInvitationCodeResp - (*InvitationRegister)(nil), // 44: openim.admin.InvitationRegister - (*SearchInvitationCodeReq)(nil), // 45: openim.admin.SearchInvitationCodeReq - (*SearchInvitationCodeResp)(nil), // 46: openim.admin.SearchInvitationCodeResp - (*SearchUserIPLimitLoginReq)(nil), // 47: openim.admin.SearchUserIPLimitLoginReq - (*LimitUserLoginIP)(nil), // 48: openim.admin.LimitUserLoginIP - (*SearchUserIPLimitLoginResp)(nil), // 49: openim.admin.SearchUserIPLimitLoginResp - (*UserIPLimitLogin)(nil), // 50: openim.admin.UserIPLimitLogin - (*AddUserIPLimitLoginReq)(nil), // 51: openim.admin.AddUserIPLimitLoginReq - (*AddUserIPLimitLoginResp)(nil), // 52: openim.admin.AddUserIPLimitLoginResp - (*DelUserIPLimitLoginReq)(nil), // 53: openim.admin.DelUserIPLimitLoginReq - (*DelUserIPLimitLoginResp)(nil), // 54: openim.admin.DelUserIPLimitLoginResp - (*IPForbidden)(nil), // 55: openim.admin.IPForbidden - (*IPForbiddenAdd)(nil), // 56: openim.admin.IPForbiddenAdd - (*SearchIPForbiddenReq)(nil), // 57: openim.admin.SearchIPForbiddenReq - (*SearchIPForbiddenResp)(nil), // 58: openim.admin.SearchIPForbiddenResp - (*AddIPForbiddenReq)(nil), // 59: openim.admin.AddIPForbiddenReq - (*AddIPForbiddenResp)(nil), // 60: openim.admin.AddIPForbiddenResp - (*DelIPForbiddenReq)(nil), // 61: openim.admin.DelIPForbiddenReq - (*DelIPForbiddenResp)(nil), // 62: openim.admin.DelIPForbiddenResp - (*CheckRegisterForbiddenReq)(nil), // 63: openim.admin.CheckRegisterForbiddenReq - (*CheckRegisterForbiddenResp)(nil), // 64: openim.admin.CheckRegisterForbiddenResp - (*CheckLoginForbiddenReq)(nil), // 65: openim.admin.CheckLoginForbiddenReq - (*CheckLoginForbiddenResp)(nil), // 66: openim.admin.CheckLoginForbiddenResp - (*CancellationUserReq)(nil), // 67: openim.admin.CancellationUserReq - (*CancellationUserResp)(nil), // 68: openim.admin.CancellationUserResp - (*BlockUserReq)(nil), // 69: openim.admin.BlockUserReq - (*BlockUserResp)(nil), // 70: openim.admin.BlockUserResp - (*UnblockUserReq)(nil), // 71: openim.admin.UnblockUserReq - (*UnblockUserResp)(nil), // 72: openim.admin.UnblockUserResp - (*SearchBlockUserReq)(nil), // 73: openim.admin.SearchBlockUserReq - (*BlockUserInfo)(nil), // 74: openim.admin.BlockUserInfo - (*SearchBlockUserResp)(nil), // 75: openim.admin.SearchBlockUserResp - (*FindUserBlockInfoReq)(nil), // 76: openim.admin.FindUserBlockInfoReq - (*BlockInfo)(nil), // 77: openim.admin.BlockInfo - (*FindUserBlockInfoResp)(nil), // 78: openim.admin.FindUserBlockInfoResp - (*CreateTokenReq)(nil), // 79: openim.admin.CreateTokenReq - (*CreateTokenResp)(nil), // 80: openim.admin.CreateTokenResp - (*ParseTokenReq)(nil), // 81: openim.admin.ParseTokenReq - (*ParseTokenResp)(nil), // 82: openim.admin.ParseTokenResp - (*InvalidateTokenReq)(nil), // 83: openim.admin.InvalidateTokenReq - (*InvalidateTokenResp)(nil), // 84: openim.admin.InvalidateTokenResp - (*AddAppletReq)(nil), // 85: openim.admin.AddAppletReq - (*AddAppletResp)(nil), // 86: openim.admin.AddAppletResp - (*DelAppletReq)(nil), // 87: openim.admin.DelAppletReq - (*DelAppletResp)(nil), // 88: openim.admin.DelAppletResp - (*UpdateAppletReq)(nil), // 89: openim.admin.UpdateAppletReq - (*UpdateAppletResp)(nil), // 90: openim.admin.UpdateAppletResp - (*FindAppletReq)(nil), // 91: openim.admin.FindAppletReq - (*FindAppletResp)(nil), // 92: openim.admin.FindAppletResp - (*SearchAppletReq)(nil), // 93: openim.admin.SearchAppletReq - (*SearchAppletResp)(nil), // 94: openim.admin.SearchAppletResp - (*SetClientConfigReq)(nil), // 95: openim.admin.SetClientConfigReq - (*SetClientConfigResp)(nil), // 96: openim.admin.SetClientConfigResp - (*DelClientConfigReq)(nil), // 97: openim.admin.DelClientConfigReq - (*DelClientConfigResp)(nil), // 98: openim.admin.DelClientConfigResp - (*GetClientConfigReq)(nil), // 99: openim.admin.GetClientConfigReq - (*GetClientConfigResp)(nil), // 100: openim.admin.GetClientConfigResp - (*GetUserTokenReq)(nil), // 101: openim.admin.GetUserTokenReq - (*GetUserTokenResp)(nil), // 102: openim.admin.GetUserTokenResp - nil, // 103: openim.admin.SetClientConfigReq.ConfigEntry - nil, // 104: openim.admin.GetClientConfigResp.ConfigEntry - nil, // 105: openim.admin.GetUserTokenResp.TokensMapEntry - (*wrapperspb.StringValue)(nil), // 106: openim.protobuf.StringValue - (*wrapperspb.Int32Value)(nil), // 107: openim.protobuf.Int32Value - (*sdkws.RequestPagination)(nil), // 108: openim.sdkws.RequestPagination - (*common.UserPublicInfo)(nil), // 109: openim.chat.common.UserPublicInfo - (*sdkws.GroupInfo)(nil), // 110: openim.sdkws.GroupInfo - (*wrapperspb.Int64Value)(nil), // 111: openim.protobuf.Int64Value - (*wrapperspb.UInt32Value)(nil), // 112: openim.protobuf.UInt32Value - (*common.AppletInfo)(nil), // 113: openim.chat.common.AppletInfo + (*LoginReq)(nil), // 0: openim.admin.LoginReq + (*LoginResp)(nil), // 1: openim.admin.LoginResp + (*AddAdminAccountReq)(nil), // 2: openim.admin.AddAdminAccountReq + (*AddAdminAccountResp)(nil), // 3: openim.admin.AddAdminAccountResp + (*AdminUpdateInfoReq)(nil), // 4: openim.admin.AdminUpdateInfoReq + (*AdminUpdateInfoResp)(nil), // 5: openim.admin.AdminUpdateInfoResp + (*ChangePasswordReq)(nil), // 6: openim.admin.ChangePasswordReq + (*ChangePasswordResp)(nil), // 7: openim.admin.ChangePasswordResp + (*GetAdminInfoReq)(nil), // 8: openim.admin.GetAdminInfoReq + (*ChangeAdminPasswordReq)(nil), // 9: openim.admin.ChangeAdminPasswordReq + (*ChangeAdminPasswordResp)(nil), // 10: openim.admin.ChangeAdminPasswordResp + (*DelAdminAccountReq)(nil), // 11: openim.admin.DelAdminAccountReq + (*DelAdminAccountResp)(nil), // 12: openim.admin.DelAdminAccountResp + (*SearchAdminAccountReq)(nil), // 13: openim.admin.SearchAdminAccountReq + (*SearchAdminAccountResp)(nil), // 14: openim.admin.SearchAdminAccountResp + (*GetAdminInfoResp)(nil), // 15: openim.admin.GetAdminInfoResp + (*AddDefaultFriendReq)(nil), // 16: openim.admin.AddDefaultFriendReq + (*AddDefaultFriendResp)(nil), // 17: openim.admin.AddDefaultFriendResp + (*DelDefaultFriendReq)(nil), // 18: openim.admin.DelDefaultFriendReq + (*DelDefaultFriendResp)(nil), // 19: openim.admin.DelDefaultFriendResp + (*FindDefaultFriendReq)(nil), // 20: openim.admin.FindDefaultFriendReq + (*FindDefaultFriendResp)(nil), // 21: openim.admin.FindDefaultFriendResp + (*SearchDefaultFriendReq)(nil), // 22: openim.admin.SearchDefaultFriendReq + (*DefaultFriendAttribute)(nil), // 23: openim.admin.DefaultFriendAttribute + (*SearchDefaultFriendResp)(nil), // 24: openim.admin.SearchDefaultFriendResp + (*AddDefaultGroupReq)(nil), // 25: openim.admin.AddDefaultGroupReq + (*AddDefaultGroupResp)(nil), // 26: openim.admin.AddDefaultGroupResp + (*DelDefaultGroupReq)(nil), // 27: openim.admin.DelDefaultGroupReq + (*DelDefaultGroupResp)(nil), // 28: openim.admin.DelDefaultGroupResp + (*FindDefaultGroupReq)(nil), // 29: openim.admin.FindDefaultGroupReq + (*FindDefaultGroupResp)(nil), // 30: openim.admin.FindDefaultGroupResp + (*SearchDefaultGroupReq)(nil), // 31: openim.admin.SearchDefaultGroupReq + (*GroupAttribute)(nil), // 32: openim.admin.GroupAttribute + (*SearchDefaultGroupResp)(nil), // 33: openim.admin.SearchDefaultGroupResp + (*AddInvitationCodeReq)(nil), // 34: openim.admin.AddInvitationCodeReq + (*AddInvitationCodeResp)(nil), // 35: openim.admin.AddInvitationCodeResp + (*GenInvitationCodeReq)(nil), // 36: openim.admin.GenInvitationCodeReq + (*GenInvitationCodeResp)(nil), // 37: openim.admin.GenInvitationCodeResp + (*FindInvitationCodeReq)(nil), // 38: openim.admin.FindInvitationCodeReq + (*FindInvitationCodeResp)(nil), // 39: openim.admin.FindInvitationCodeResp + (*UseInvitationCodeReq)(nil), // 40: openim.admin.UseInvitationCodeReq + (*UseInvitationCodeResp)(nil), // 41: openim.admin.UseInvitationCodeResp + (*DelInvitationCodeReq)(nil), // 42: openim.admin.DelInvitationCodeReq + (*DelInvitationCodeResp)(nil), // 43: openim.admin.DelInvitationCodeResp + (*InvitationRegister)(nil), // 44: openim.admin.InvitationRegister + (*SearchInvitationCodeReq)(nil), // 45: openim.admin.SearchInvitationCodeReq + (*SearchInvitationCodeResp)(nil), // 46: openim.admin.SearchInvitationCodeResp + (*SearchUserIPLimitLoginReq)(nil), // 47: openim.admin.SearchUserIPLimitLoginReq + (*LimitUserLoginIP)(nil), // 48: openim.admin.LimitUserLoginIP + (*SearchUserIPLimitLoginResp)(nil), // 49: openim.admin.SearchUserIPLimitLoginResp + (*UserIPLimitLogin)(nil), // 50: openim.admin.UserIPLimitLogin + (*AddUserIPLimitLoginReq)(nil), // 51: openim.admin.AddUserIPLimitLoginReq + (*AddUserIPLimitLoginResp)(nil), // 52: openim.admin.AddUserIPLimitLoginResp + (*DelUserIPLimitLoginReq)(nil), // 53: openim.admin.DelUserIPLimitLoginReq + (*DelUserIPLimitLoginResp)(nil), // 54: openim.admin.DelUserIPLimitLoginResp + (*IPForbidden)(nil), // 55: openim.admin.IPForbidden + (*IPForbiddenAdd)(nil), // 56: openim.admin.IPForbiddenAdd + (*SearchIPForbiddenReq)(nil), // 57: openim.admin.SearchIPForbiddenReq + (*SearchIPForbiddenResp)(nil), // 58: openim.admin.SearchIPForbiddenResp + (*AddIPForbiddenReq)(nil), // 59: openim.admin.AddIPForbiddenReq + (*AddIPForbiddenResp)(nil), // 60: openim.admin.AddIPForbiddenResp + (*DelIPForbiddenReq)(nil), // 61: openim.admin.DelIPForbiddenReq + (*DelIPForbiddenResp)(nil), // 62: openim.admin.DelIPForbiddenResp + (*CheckRegisterForbiddenReq)(nil), // 63: openim.admin.CheckRegisterForbiddenReq + (*CheckRegisterForbiddenResp)(nil), // 64: openim.admin.CheckRegisterForbiddenResp + (*CheckLoginForbiddenReq)(nil), // 65: openim.admin.CheckLoginForbiddenReq + (*CheckLoginForbiddenResp)(nil), // 66: openim.admin.CheckLoginForbiddenResp + (*CancellationUserReq)(nil), // 67: openim.admin.CancellationUserReq + (*CancellationUserResp)(nil), // 68: openim.admin.CancellationUserResp + (*BlockUserReq)(nil), // 69: openim.admin.BlockUserReq + (*BlockUserResp)(nil), // 70: openim.admin.BlockUserResp + (*UnblockUserReq)(nil), // 71: openim.admin.UnblockUserReq + (*UnblockUserResp)(nil), // 72: openim.admin.UnblockUserResp + (*SearchBlockUserReq)(nil), // 73: openim.admin.SearchBlockUserReq + (*BlockUserInfo)(nil), // 74: openim.admin.BlockUserInfo + (*SearchBlockUserResp)(nil), // 75: openim.admin.SearchBlockUserResp + (*FindUserBlockInfoReq)(nil), // 76: openim.admin.FindUserBlockInfoReq + (*BlockInfo)(nil), // 77: openim.admin.BlockInfo + (*FindUserBlockInfoResp)(nil), // 78: openim.admin.FindUserBlockInfoResp + (*CreateTokenReq)(nil), // 79: openim.admin.CreateTokenReq + (*CreateTokenResp)(nil), // 80: openim.admin.CreateTokenResp + (*ParseTokenReq)(nil), // 81: openim.admin.ParseTokenReq + (*ParseTokenResp)(nil), // 82: openim.admin.ParseTokenResp + (*InvalidateTokenReq)(nil), // 83: openim.admin.InvalidateTokenReq + (*InvalidateTokenResp)(nil), // 84: openim.admin.InvalidateTokenResp + (*AddAppletReq)(nil), // 85: openim.admin.AddAppletReq + (*AddAppletResp)(nil), // 86: openim.admin.AddAppletResp + (*DelAppletReq)(nil), // 87: openim.admin.DelAppletReq + (*DelAppletResp)(nil), // 88: openim.admin.DelAppletResp + (*UpdateAppletReq)(nil), // 89: openim.admin.UpdateAppletReq + (*UpdateAppletResp)(nil), // 90: openim.admin.UpdateAppletResp + (*FindAppletReq)(nil), // 91: openim.admin.FindAppletReq + (*FindAppletResp)(nil), // 92: openim.admin.FindAppletResp + (*SearchAppletReq)(nil), // 93: openim.admin.SearchAppletReq + (*SearchAppletResp)(nil), // 94: openim.admin.SearchAppletResp + (*SetClientConfigReq)(nil), // 95: openim.admin.SetClientConfigReq + (*SetClientConfigResp)(nil), // 96: openim.admin.SetClientConfigResp + (*DelClientConfigReq)(nil), // 97: openim.admin.DelClientConfigReq + (*DelClientConfigResp)(nil), // 98: openim.admin.DelClientConfigResp + (*GetClientConfigReq)(nil), // 99: openim.admin.GetClientConfigReq + (*GetClientConfigResp)(nil), // 100: openim.admin.GetClientConfigResp + (*GetUserTokenReq)(nil), // 101: openim.admin.GetUserTokenReq + (*GetUserTokenResp)(nil), // 102: openim.admin.GetUserTokenResp + (*ApplicationVersion)(nil), // 103: openim.admin.ApplicationVersion + (*LatestApplicationVersionReq)(nil), // 104: openim.admin.LatestApplicationVersionReq + (*LatestApplicationVersionResp)(nil), // 105: openim.admin.LatestApplicationVersionResp + (*AddApplicationVersionReq)(nil), // 106: openim.admin.AddApplicationVersionReq + (*AddApplicationVersionResp)(nil), // 107: openim.admin.AddApplicationVersionResp + (*UpdateApplicationVersionReq)(nil), // 108: openim.admin.UpdateApplicationVersionReq + (*UpdateApplicationVersionResp)(nil), // 109: openim.admin.UpdateApplicationVersionResp + (*DeleteApplicationVersionReq)(nil), // 110: openim.admin.DeleteApplicationVersionReq + (*DeleteApplicationVersionResp)(nil), // 111: openim.admin.DeleteApplicationVersionResp + (*PageApplicationVersionReq)(nil), // 112: openim.admin.PageApplicationVersionReq + (*PageApplicationVersionResp)(nil), // 113: openim.admin.PageApplicationVersionResp + nil, // 114: openim.admin.SetClientConfigReq.ConfigEntry + nil, // 115: openim.admin.GetClientConfigResp.ConfigEntry + nil, // 116: openim.admin.GetUserTokenResp.TokensMapEntry + (*wrapperspb.StringValue)(nil), // 117: openim.protobuf.StringValue + (*wrapperspb.Int32Value)(nil), // 118: openim.protobuf.Int32Value + (*sdkws.RequestPagination)(nil), // 119: openim.sdkws.RequestPagination + (*common.UserPublicInfo)(nil), // 120: openim.chat.common.UserPublicInfo + (*sdkws.GroupInfo)(nil), // 121: openim.sdkws.GroupInfo + (*wrapperspb.Int64Value)(nil), // 122: openim.protobuf.Int64Value + (*wrapperspb.UInt32Value)(nil), // 123: openim.protobuf.UInt32Value + (*common.AppletInfo)(nil), // 124: openim.chat.common.AppletInfo + (*wrapperspb.BoolValue)(nil), // 125: openim.protobuf.BoolValue } var file_admin_admin_proto_depIdxs = []int32{ - 106, // 0: openim.admin.AdminUpdateInfoReq.account:type_name -> openim.protobuf.StringValue - 106, // 1: openim.admin.AdminUpdateInfoReq.password:type_name -> openim.protobuf.StringValue - 106, // 2: openim.admin.AdminUpdateInfoReq.faceURL:type_name -> openim.protobuf.StringValue - 106, // 3: openim.admin.AdminUpdateInfoReq.nickname:type_name -> openim.protobuf.StringValue - 107, // 4: openim.admin.AdminUpdateInfoReq.level:type_name -> openim.protobuf.Int32Value - 108, // 5: openim.admin.SearchAdminAccountReq.pagination:type_name -> openim.sdkws.RequestPagination + 117, // 0: openim.admin.AdminUpdateInfoReq.account:type_name -> openim.protobuf.StringValue + 117, // 1: openim.admin.AdminUpdateInfoReq.password:type_name -> openim.protobuf.StringValue + 117, // 2: openim.admin.AdminUpdateInfoReq.faceURL:type_name -> openim.protobuf.StringValue + 117, // 3: openim.admin.AdminUpdateInfoReq.nickname:type_name -> openim.protobuf.StringValue + 118, // 4: openim.admin.AdminUpdateInfoReq.level:type_name -> openim.protobuf.Int32Value + 119, // 5: openim.admin.SearchAdminAccountReq.pagination:type_name -> openim.sdkws.RequestPagination 15, // 6: openim.admin.SearchAdminAccountResp.adminAccounts:type_name -> openim.admin.GetAdminInfoResp - 108, // 7: openim.admin.SearchDefaultFriendReq.pagination:type_name -> openim.sdkws.RequestPagination - 109, // 8: openim.admin.DefaultFriendAttribute.user:type_name -> openim.chat.common.UserPublicInfo + 119, // 7: openim.admin.SearchDefaultFriendReq.pagination:type_name -> openim.sdkws.RequestPagination + 120, // 8: openim.admin.DefaultFriendAttribute.user:type_name -> openim.chat.common.UserPublicInfo 23, // 9: openim.admin.SearchDefaultFriendResp.users:type_name -> openim.admin.DefaultFriendAttribute - 108, // 10: openim.admin.SearchDefaultGroupReq.pagination:type_name -> openim.sdkws.RequestPagination - 110, // 11: openim.admin.GroupAttribute.group:type_name -> openim.sdkws.GroupInfo + 119, // 10: openim.admin.SearchDefaultGroupReq.pagination:type_name -> openim.sdkws.RequestPagination + 121, // 11: openim.admin.GroupAttribute.group:type_name -> openim.sdkws.GroupInfo 44, // 12: openim.admin.FindInvitationCodeResp.codes:type_name -> openim.admin.InvitationRegister - 109, // 13: openim.admin.InvitationRegister.usedUser:type_name -> openim.chat.common.UserPublicInfo - 108, // 14: openim.admin.SearchInvitationCodeReq.pagination:type_name -> openim.sdkws.RequestPagination + 120, // 13: openim.admin.InvitationRegister.usedUser:type_name -> openim.chat.common.UserPublicInfo + 119, // 14: openim.admin.SearchInvitationCodeReq.pagination:type_name -> openim.sdkws.RequestPagination 44, // 15: openim.admin.SearchInvitationCodeResp.list:type_name -> openim.admin.InvitationRegister - 108, // 16: openim.admin.SearchUserIPLimitLoginReq.pagination:type_name -> openim.sdkws.RequestPagination - 109, // 17: openim.admin.LimitUserLoginIP.user:type_name -> openim.chat.common.UserPublicInfo + 119, // 16: openim.admin.SearchUserIPLimitLoginReq.pagination:type_name -> openim.sdkws.RequestPagination + 120, // 17: openim.admin.LimitUserLoginIP.user:type_name -> openim.chat.common.UserPublicInfo 48, // 18: openim.admin.SearchUserIPLimitLoginResp.limits:type_name -> openim.admin.LimitUserLoginIP 50, // 19: openim.admin.AddUserIPLimitLoginReq.limits:type_name -> openim.admin.UserIPLimitLogin 50, // 20: openim.admin.DelUserIPLimitLoginReq.limits:type_name -> openim.admin.UserIPLimitLogin - 108, // 21: openim.admin.SearchIPForbiddenReq.pagination:type_name -> openim.sdkws.RequestPagination + 119, // 21: openim.admin.SearchIPForbiddenReq.pagination:type_name -> openim.sdkws.RequestPagination 55, // 22: openim.admin.SearchIPForbiddenResp.forbiddens:type_name -> openim.admin.IPForbidden 56, // 23: openim.admin.AddIPForbiddenReq.forbiddens:type_name -> openim.admin.IPForbiddenAdd - 108, // 24: openim.admin.SearchBlockUserReq.pagination:type_name -> openim.sdkws.RequestPagination + 119, // 24: openim.admin.SearchBlockUserReq.pagination:type_name -> openim.sdkws.RequestPagination 74, // 25: openim.admin.SearchBlockUserResp.users:type_name -> openim.admin.BlockUserInfo 77, // 26: openim.admin.FindUserBlockInfoResp.blocks:type_name -> openim.admin.BlockInfo - 106, // 27: openim.admin.UpdateAppletReq.name:type_name -> openim.protobuf.StringValue - 106, // 28: openim.admin.UpdateAppletReq.appID:type_name -> openim.protobuf.StringValue - 106, // 29: openim.admin.UpdateAppletReq.icon:type_name -> openim.protobuf.StringValue - 106, // 30: openim.admin.UpdateAppletReq.url:type_name -> openim.protobuf.StringValue - 106, // 31: openim.admin.UpdateAppletReq.md5:type_name -> openim.protobuf.StringValue - 111, // 32: openim.admin.UpdateAppletReq.size:type_name -> openim.protobuf.Int64Value - 106, // 33: openim.admin.UpdateAppletReq.version:type_name -> openim.protobuf.StringValue - 112, // 34: openim.admin.UpdateAppletReq.priority:type_name -> openim.protobuf.UInt32Value - 112, // 35: openim.admin.UpdateAppletReq.status:type_name -> openim.protobuf.UInt32Value - 111, // 36: openim.admin.UpdateAppletReq.createTime:type_name -> openim.protobuf.Int64Value - 113, // 37: openim.admin.FindAppletResp.applets:type_name -> openim.chat.common.AppletInfo - 108, // 38: openim.admin.SearchAppletReq.pagination:type_name -> openim.sdkws.RequestPagination - 113, // 39: openim.admin.SearchAppletResp.applets:type_name -> openim.chat.common.AppletInfo - 103, // 40: openim.admin.SetClientConfigReq.config:type_name -> openim.admin.SetClientConfigReq.ConfigEntry - 104, // 41: openim.admin.GetClientConfigResp.config:type_name -> openim.admin.GetClientConfigResp.ConfigEntry - 105, // 42: openim.admin.GetUserTokenResp.tokensMap:type_name -> openim.admin.GetUserTokenResp.TokensMapEntry - 0, // 43: openim.admin.admin.Login:input_type -> openim.admin.LoginReq - 6, // 44: openim.admin.admin.ChangePassword:input_type -> openim.admin.ChangePasswordReq - 4, // 45: openim.admin.admin.AdminUpdateInfo:input_type -> openim.admin.AdminUpdateInfoReq - 8, // 46: openim.admin.admin.GetAdminInfo:input_type -> openim.admin.GetAdminInfoReq - 2, // 47: openim.admin.admin.AddAdminAccount:input_type -> openim.admin.AddAdminAccountReq - 9, // 48: openim.admin.admin.ChangeAdminPassword:input_type -> openim.admin.ChangeAdminPasswordReq - 11, // 49: openim.admin.admin.DelAdminAccount:input_type -> openim.admin.DelAdminAccountReq - 13, // 50: openim.admin.admin.SearchAdminAccount:input_type -> openim.admin.SearchAdminAccountReq - 16, // 51: openim.admin.admin.AddDefaultFriend:input_type -> openim.admin.AddDefaultFriendReq - 18, // 52: openim.admin.admin.DelDefaultFriend:input_type -> openim.admin.DelDefaultFriendReq - 20, // 53: openim.admin.admin.FindDefaultFriend:input_type -> openim.admin.FindDefaultFriendReq - 22, // 54: openim.admin.admin.SearchDefaultFriend:input_type -> openim.admin.SearchDefaultFriendReq - 25, // 55: openim.admin.admin.AddDefaultGroup:input_type -> openim.admin.AddDefaultGroupReq - 27, // 56: openim.admin.admin.DelDefaultGroup:input_type -> openim.admin.DelDefaultGroupReq - 29, // 57: openim.admin.admin.FindDefaultGroup:input_type -> openim.admin.FindDefaultGroupReq - 31, // 58: openim.admin.admin.SearchDefaultGroup:input_type -> openim.admin.SearchDefaultGroupReq - 34, // 59: openim.admin.admin.AddInvitationCode:input_type -> openim.admin.AddInvitationCodeReq - 36, // 60: openim.admin.admin.GenInvitationCode:input_type -> openim.admin.GenInvitationCodeReq - 38, // 61: openim.admin.admin.FindInvitationCode:input_type -> openim.admin.FindInvitationCodeReq - 40, // 62: openim.admin.admin.UseInvitationCode:input_type -> openim.admin.UseInvitationCodeReq - 42, // 63: openim.admin.admin.DelInvitationCode:input_type -> openim.admin.DelInvitationCodeReq - 45, // 64: openim.admin.admin.SearchInvitationCode:input_type -> openim.admin.SearchInvitationCodeReq - 47, // 65: openim.admin.admin.SearchUserIPLimitLogin:input_type -> openim.admin.SearchUserIPLimitLoginReq - 51, // 66: openim.admin.admin.AddUserIPLimitLogin:input_type -> openim.admin.AddUserIPLimitLoginReq - 53, // 67: openim.admin.admin.DelUserIPLimitLogin:input_type -> openim.admin.DelUserIPLimitLoginReq - 57, // 68: openim.admin.admin.SearchIPForbidden:input_type -> openim.admin.SearchIPForbiddenReq - 59, // 69: openim.admin.admin.AddIPForbidden:input_type -> openim.admin.AddIPForbiddenReq - 61, // 70: openim.admin.admin.DelIPForbidden:input_type -> openim.admin.DelIPForbiddenReq - 67, // 71: openim.admin.admin.CancellationUser:input_type -> openim.admin.CancellationUserReq - 69, // 72: openim.admin.admin.BlockUser:input_type -> openim.admin.BlockUserReq - 71, // 73: openim.admin.admin.UnblockUser:input_type -> openim.admin.UnblockUserReq - 73, // 74: openim.admin.admin.SearchBlockUser:input_type -> openim.admin.SearchBlockUserReq - 76, // 75: openim.admin.admin.FindUserBlockInfo:input_type -> openim.admin.FindUserBlockInfoReq - 63, // 76: openim.admin.admin.CheckRegisterForbidden:input_type -> openim.admin.CheckRegisterForbiddenReq - 65, // 77: openim.admin.admin.CheckLoginForbidden:input_type -> openim.admin.CheckLoginForbiddenReq - 79, // 78: openim.admin.admin.CreateToken:input_type -> openim.admin.CreateTokenReq - 81, // 79: openim.admin.admin.ParseToken:input_type -> openim.admin.ParseTokenReq - 85, // 80: openim.admin.admin.AddApplet:input_type -> openim.admin.AddAppletReq - 87, // 81: openim.admin.admin.DelApplet:input_type -> openim.admin.DelAppletReq - 89, // 82: openim.admin.admin.UpdateApplet:input_type -> openim.admin.UpdateAppletReq - 91, // 83: openim.admin.admin.FindApplet:input_type -> openim.admin.FindAppletReq - 93, // 84: openim.admin.admin.SearchApplet:input_type -> openim.admin.SearchAppletReq - 99, // 85: openim.admin.admin.GetClientConfig:input_type -> openim.admin.GetClientConfigReq - 95, // 86: openim.admin.admin.SetClientConfig:input_type -> openim.admin.SetClientConfigReq - 97, // 87: openim.admin.admin.DelClientConfig:input_type -> openim.admin.DelClientConfigReq - 101, // 88: openim.admin.admin.GetUserToken:input_type -> openim.admin.GetUserTokenReq - 83, // 89: openim.admin.admin.InvalidateToken:input_type -> openim.admin.InvalidateTokenReq - 1, // 90: openim.admin.admin.Login:output_type -> openim.admin.LoginResp - 7, // 91: openim.admin.admin.ChangePassword:output_type -> openim.admin.ChangePasswordResp - 5, // 92: openim.admin.admin.AdminUpdateInfo:output_type -> openim.admin.AdminUpdateInfoResp - 15, // 93: openim.admin.admin.GetAdminInfo:output_type -> openim.admin.GetAdminInfoResp - 3, // 94: openim.admin.admin.AddAdminAccount:output_type -> openim.admin.AddAdminAccountResp - 10, // 95: openim.admin.admin.ChangeAdminPassword:output_type -> openim.admin.ChangeAdminPasswordResp - 12, // 96: openim.admin.admin.DelAdminAccount:output_type -> openim.admin.DelAdminAccountResp - 14, // 97: openim.admin.admin.SearchAdminAccount:output_type -> openim.admin.SearchAdminAccountResp - 17, // 98: openim.admin.admin.AddDefaultFriend:output_type -> openim.admin.AddDefaultFriendResp - 19, // 99: openim.admin.admin.DelDefaultFriend:output_type -> openim.admin.DelDefaultFriendResp - 21, // 100: openim.admin.admin.FindDefaultFriend:output_type -> openim.admin.FindDefaultFriendResp - 24, // 101: openim.admin.admin.SearchDefaultFriend:output_type -> openim.admin.SearchDefaultFriendResp - 26, // 102: openim.admin.admin.AddDefaultGroup:output_type -> openim.admin.AddDefaultGroupResp - 28, // 103: openim.admin.admin.DelDefaultGroup:output_type -> openim.admin.DelDefaultGroupResp - 30, // 104: openim.admin.admin.FindDefaultGroup:output_type -> openim.admin.FindDefaultGroupResp - 33, // 105: openim.admin.admin.SearchDefaultGroup:output_type -> openim.admin.SearchDefaultGroupResp - 35, // 106: openim.admin.admin.AddInvitationCode:output_type -> openim.admin.AddInvitationCodeResp - 37, // 107: openim.admin.admin.GenInvitationCode:output_type -> openim.admin.GenInvitationCodeResp - 39, // 108: openim.admin.admin.FindInvitationCode:output_type -> openim.admin.FindInvitationCodeResp - 41, // 109: openim.admin.admin.UseInvitationCode:output_type -> openim.admin.UseInvitationCodeResp - 43, // 110: openim.admin.admin.DelInvitationCode:output_type -> openim.admin.DelInvitationCodeResp - 46, // 111: openim.admin.admin.SearchInvitationCode:output_type -> openim.admin.SearchInvitationCodeResp - 49, // 112: openim.admin.admin.SearchUserIPLimitLogin:output_type -> openim.admin.SearchUserIPLimitLoginResp - 52, // 113: openim.admin.admin.AddUserIPLimitLogin:output_type -> openim.admin.AddUserIPLimitLoginResp - 54, // 114: openim.admin.admin.DelUserIPLimitLogin:output_type -> openim.admin.DelUserIPLimitLoginResp - 58, // 115: openim.admin.admin.SearchIPForbidden:output_type -> openim.admin.SearchIPForbiddenResp - 60, // 116: openim.admin.admin.AddIPForbidden:output_type -> openim.admin.AddIPForbiddenResp - 62, // 117: openim.admin.admin.DelIPForbidden:output_type -> openim.admin.DelIPForbiddenResp - 68, // 118: openim.admin.admin.CancellationUser:output_type -> openim.admin.CancellationUserResp - 70, // 119: openim.admin.admin.BlockUser:output_type -> openim.admin.BlockUserResp - 72, // 120: openim.admin.admin.UnblockUser:output_type -> openim.admin.UnblockUserResp - 75, // 121: openim.admin.admin.SearchBlockUser:output_type -> openim.admin.SearchBlockUserResp - 78, // 122: openim.admin.admin.FindUserBlockInfo:output_type -> openim.admin.FindUserBlockInfoResp - 64, // 123: openim.admin.admin.CheckRegisterForbidden:output_type -> openim.admin.CheckRegisterForbiddenResp - 66, // 124: openim.admin.admin.CheckLoginForbidden:output_type -> openim.admin.CheckLoginForbiddenResp - 80, // 125: openim.admin.admin.CreateToken:output_type -> openim.admin.CreateTokenResp - 82, // 126: openim.admin.admin.ParseToken:output_type -> openim.admin.ParseTokenResp - 86, // 127: openim.admin.admin.AddApplet:output_type -> openim.admin.AddAppletResp - 88, // 128: openim.admin.admin.DelApplet:output_type -> openim.admin.DelAppletResp - 90, // 129: openim.admin.admin.UpdateApplet:output_type -> openim.admin.UpdateAppletResp - 92, // 130: openim.admin.admin.FindApplet:output_type -> openim.admin.FindAppletResp - 94, // 131: openim.admin.admin.SearchApplet:output_type -> openim.admin.SearchAppletResp - 100, // 132: openim.admin.admin.GetClientConfig:output_type -> openim.admin.GetClientConfigResp - 96, // 133: openim.admin.admin.SetClientConfig:output_type -> openim.admin.SetClientConfigResp - 98, // 134: openim.admin.admin.DelClientConfig:output_type -> openim.admin.DelClientConfigResp - 102, // 135: openim.admin.admin.GetUserToken:output_type -> openim.admin.GetUserTokenResp - 84, // 136: openim.admin.admin.InvalidateToken:output_type -> openim.admin.InvalidateTokenResp - 90, // [90:137] is the sub-list for method output_type - 43, // [43:90] is the sub-list for method input_type - 43, // [43:43] is the sub-list for extension type_name - 43, // [43:43] is the sub-list for extension extendee - 0, // [0:43] is the sub-list for field type_name + 117, // 27: openim.admin.UpdateAppletReq.name:type_name -> openim.protobuf.StringValue + 117, // 28: openim.admin.UpdateAppletReq.appID:type_name -> openim.protobuf.StringValue + 117, // 29: openim.admin.UpdateAppletReq.icon:type_name -> openim.protobuf.StringValue + 117, // 30: openim.admin.UpdateAppletReq.url:type_name -> openim.protobuf.StringValue + 117, // 31: openim.admin.UpdateAppletReq.md5:type_name -> openim.protobuf.StringValue + 122, // 32: openim.admin.UpdateAppletReq.size:type_name -> openim.protobuf.Int64Value + 117, // 33: openim.admin.UpdateAppletReq.version:type_name -> openim.protobuf.StringValue + 123, // 34: openim.admin.UpdateAppletReq.priority:type_name -> openim.protobuf.UInt32Value + 123, // 35: openim.admin.UpdateAppletReq.status:type_name -> openim.protobuf.UInt32Value + 122, // 36: openim.admin.UpdateAppletReq.createTime:type_name -> openim.protobuf.Int64Value + 124, // 37: openim.admin.FindAppletResp.applets:type_name -> openim.chat.common.AppletInfo + 119, // 38: openim.admin.SearchAppletReq.pagination:type_name -> openim.sdkws.RequestPagination + 124, // 39: openim.admin.SearchAppletResp.applets:type_name -> openim.chat.common.AppletInfo + 114, // 40: openim.admin.SetClientConfigReq.config:type_name -> openim.admin.SetClientConfigReq.ConfigEntry + 115, // 41: openim.admin.GetClientConfigResp.config:type_name -> openim.admin.GetClientConfigResp.ConfigEntry + 116, // 42: openim.admin.GetUserTokenResp.tokensMap:type_name -> openim.admin.GetUserTokenResp.TokensMapEntry + 103, // 43: openim.admin.LatestApplicationVersionResp.version:type_name -> openim.admin.ApplicationVersion + 117, // 44: openim.admin.UpdateApplicationVersionReq.platform:type_name -> openim.protobuf.StringValue + 117, // 45: openim.admin.UpdateApplicationVersionReq.version:type_name -> openim.protobuf.StringValue + 117, // 46: openim.admin.UpdateApplicationVersionReq.url:type_name -> openim.protobuf.StringValue + 117, // 47: openim.admin.UpdateApplicationVersionReq.text:type_name -> openim.protobuf.StringValue + 125, // 48: openim.admin.UpdateApplicationVersionReq.force:type_name -> openim.protobuf.BoolValue + 125, // 49: openim.admin.UpdateApplicationVersionReq.latest:type_name -> openim.protobuf.BoolValue + 125, // 50: openim.admin.UpdateApplicationVersionReq.hot:type_name -> openim.protobuf.BoolValue + 119, // 51: openim.admin.PageApplicationVersionReq.pagination:type_name -> openim.sdkws.RequestPagination + 103, // 52: openim.admin.PageApplicationVersionResp.versions:type_name -> openim.admin.ApplicationVersion + 0, // 53: openim.admin.admin.Login:input_type -> openim.admin.LoginReq + 6, // 54: openim.admin.admin.ChangePassword:input_type -> openim.admin.ChangePasswordReq + 4, // 55: openim.admin.admin.AdminUpdateInfo:input_type -> openim.admin.AdminUpdateInfoReq + 8, // 56: openim.admin.admin.GetAdminInfo:input_type -> openim.admin.GetAdminInfoReq + 2, // 57: openim.admin.admin.AddAdminAccount:input_type -> openim.admin.AddAdminAccountReq + 9, // 58: openim.admin.admin.ChangeAdminPassword:input_type -> openim.admin.ChangeAdminPasswordReq + 11, // 59: openim.admin.admin.DelAdminAccount:input_type -> openim.admin.DelAdminAccountReq + 13, // 60: openim.admin.admin.SearchAdminAccount:input_type -> openim.admin.SearchAdminAccountReq + 16, // 61: openim.admin.admin.AddDefaultFriend:input_type -> openim.admin.AddDefaultFriendReq + 18, // 62: openim.admin.admin.DelDefaultFriend:input_type -> openim.admin.DelDefaultFriendReq + 20, // 63: openim.admin.admin.FindDefaultFriend:input_type -> openim.admin.FindDefaultFriendReq + 22, // 64: openim.admin.admin.SearchDefaultFriend:input_type -> openim.admin.SearchDefaultFriendReq + 25, // 65: openim.admin.admin.AddDefaultGroup:input_type -> openim.admin.AddDefaultGroupReq + 27, // 66: openim.admin.admin.DelDefaultGroup:input_type -> openim.admin.DelDefaultGroupReq + 29, // 67: openim.admin.admin.FindDefaultGroup:input_type -> openim.admin.FindDefaultGroupReq + 31, // 68: openim.admin.admin.SearchDefaultGroup:input_type -> openim.admin.SearchDefaultGroupReq + 34, // 69: openim.admin.admin.AddInvitationCode:input_type -> openim.admin.AddInvitationCodeReq + 36, // 70: openim.admin.admin.GenInvitationCode:input_type -> openim.admin.GenInvitationCodeReq + 38, // 71: openim.admin.admin.FindInvitationCode:input_type -> openim.admin.FindInvitationCodeReq + 40, // 72: openim.admin.admin.UseInvitationCode:input_type -> openim.admin.UseInvitationCodeReq + 42, // 73: openim.admin.admin.DelInvitationCode:input_type -> openim.admin.DelInvitationCodeReq + 45, // 74: openim.admin.admin.SearchInvitationCode:input_type -> openim.admin.SearchInvitationCodeReq + 47, // 75: openim.admin.admin.SearchUserIPLimitLogin:input_type -> openim.admin.SearchUserIPLimitLoginReq + 51, // 76: openim.admin.admin.AddUserIPLimitLogin:input_type -> openim.admin.AddUserIPLimitLoginReq + 53, // 77: openim.admin.admin.DelUserIPLimitLogin:input_type -> openim.admin.DelUserIPLimitLoginReq + 57, // 78: openim.admin.admin.SearchIPForbidden:input_type -> openim.admin.SearchIPForbiddenReq + 59, // 79: openim.admin.admin.AddIPForbidden:input_type -> openim.admin.AddIPForbiddenReq + 61, // 80: openim.admin.admin.DelIPForbidden:input_type -> openim.admin.DelIPForbiddenReq + 67, // 81: openim.admin.admin.CancellationUser:input_type -> openim.admin.CancellationUserReq + 69, // 82: openim.admin.admin.BlockUser:input_type -> openim.admin.BlockUserReq + 71, // 83: openim.admin.admin.UnblockUser:input_type -> openim.admin.UnblockUserReq + 73, // 84: openim.admin.admin.SearchBlockUser:input_type -> openim.admin.SearchBlockUserReq + 76, // 85: openim.admin.admin.FindUserBlockInfo:input_type -> openim.admin.FindUserBlockInfoReq + 63, // 86: openim.admin.admin.CheckRegisterForbidden:input_type -> openim.admin.CheckRegisterForbiddenReq + 65, // 87: openim.admin.admin.CheckLoginForbidden:input_type -> openim.admin.CheckLoginForbiddenReq + 79, // 88: openim.admin.admin.CreateToken:input_type -> openim.admin.CreateTokenReq + 81, // 89: openim.admin.admin.ParseToken:input_type -> openim.admin.ParseTokenReq + 85, // 90: openim.admin.admin.AddApplet:input_type -> openim.admin.AddAppletReq + 87, // 91: openim.admin.admin.DelApplet:input_type -> openim.admin.DelAppletReq + 89, // 92: openim.admin.admin.UpdateApplet:input_type -> openim.admin.UpdateAppletReq + 91, // 93: openim.admin.admin.FindApplet:input_type -> openim.admin.FindAppletReq + 93, // 94: openim.admin.admin.SearchApplet:input_type -> openim.admin.SearchAppletReq + 99, // 95: openim.admin.admin.GetClientConfig:input_type -> openim.admin.GetClientConfigReq + 95, // 96: openim.admin.admin.SetClientConfig:input_type -> openim.admin.SetClientConfigReq + 97, // 97: openim.admin.admin.DelClientConfig:input_type -> openim.admin.DelClientConfigReq + 101, // 98: openim.admin.admin.GetUserToken:input_type -> openim.admin.GetUserTokenReq + 83, // 99: openim.admin.admin.InvalidateToken:input_type -> openim.admin.InvalidateTokenReq + 104, // 100: openim.admin.admin.LatestApplicationVersion:input_type -> openim.admin.LatestApplicationVersionReq + 106, // 101: openim.admin.admin.AddApplicationVersion:input_type -> openim.admin.AddApplicationVersionReq + 108, // 102: openim.admin.admin.UpdateApplicationVersion:input_type -> openim.admin.UpdateApplicationVersionReq + 110, // 103: openim.admin.admin.DeleteApplicationVersion:input_type -> openim.admin.DeleteApplicationVersionReq + 112, // 104: openim.admin.admin.PageApplicationVersion:input_type -> openim.admin.PageApplicationVersionReq + 1, // 105: openim.admin.admin.Login:output_type -> openim.admin.LoginResp + 7, // 106: openim.admin.admin.ChangePassword:output_type -> openim.admin.ChangePasswordResp + 5, // 107: openim.admin.admin.AdminUpdateInfo:output_type -> openim.admin.AdminUpdateInfoResp + 15, // 108: openim.admin.admin.GetAdminInfo:output_type -> openim.admin.GetAdminInfoResp + 3, // 109: openim.admin.admin.AddAdminAccount:output_type -> openim.admin.AddAdminAccountResp + 10, // 110: openim.admin.admin.ChangeAdminPassword:output_type -> openim.admin.ChangeAdminPasswordResp + 12, // 111: openim.admin.admin.DelAdminAccount:output_type -> openim.admin.DelAdminAccountResp + 14, // 112: openim.admin.admin.SearchAdminAccount:output_type -> openim.admin.SearchAdminAccountResp + 17, // 113: openim.admin.admin.AddDefaultFriend:output_type -> openim.admin.AddDefaultFriendResp + 19, // 114: openim.admin.admin.DelDefaultFriend:output_type -> openim.admin.DelDefaultFriendResp + 21, // 115: openim.admin.admin.FindDefaultFriend:output_type -> openim.admin.FindDefaultFriendResp + 24, // 116: openim.admin.admin.SearchDefaultFriend:output_type -> openim.admin.SearchDefaultFriendResp + 26, // 117: openim.admin.admin.AddDefaultGroup:output_type -> openim.admin.AddDefaultGroupResp + 28, // 118: openim.admin.admin.DelDefaultGroup:output_type -> openim.admin.DelDefaultGroupResp + 30, // 119: openim.admin.admin.FindDefaultGroup:output_type -> openim.admin.FindDefaultGroupResp + 33, // 120: openim.admin.admin.SearchDefaultGroup:output_type -> openim.admin.SearchDefaultGroupResp + 35, // 121: openim.admin.admin.AddInvitationCode:output_type -> openim.admin.AddInvitationCodeResp + 37, // 122: openim.admin.admin.GenInvitationCode:output_type -> openim.admin.GenInvitationCodeResp + 39, // 123: openim.admin.admin.FindInvitationCode:output_type -> openim.admin.FindInvitationCodeResp + 41, // 124: openim.admin.admin.UseInvitationCode:output_type -> openim.admin.UseInvitationCodeResp + 43, // 125: openim.admin.admin.DelInvitationCode:output_type -> openim.admin.DelInvitationCodeResp + 46, // 126: openim.admin.admin.SearchInvitationCode:output_type -> openim.admin.SearchInvitationCodeResp + 49, // 127: openim.admin.admin.SearchUserIPLimitLogin:output_type -> openim.admin.SearchUserIPLimitLoginResp + 52, // 128: openim.admin.admin.AddUserIPLimitLogin:output_type -> openim.admin.AddUserIPLimitLoginResp + 54, // 129: openim.admin.admin.DelUserIPLimitLogin:output_type -> openim.admin.DelUserIPLimitLoginResp + 58, // 130: openim.admin.admin.SearchIPForbidden:output_type -> openim.admin.SearchIPForbiddenResp + 60, // 131: openim.admin.admin.AddIPForbidden:output_type -> openim.admin.AddIPForbiddenResp + 62, // 132: openim.admin.admin.DelIPForbidden:output_type -> openim.admin.DelIPForbiddenResp + 68, // 133: openim.admin.admin.CancellationUser:output_type -> openim.admin.CancellationUserResp + 70, // 134: openim.admin.admin.BlockUser:output_type -> openim.admin.BlockUserResp + 72, // 135: openim.admin.admin.UnblockUser:output_type -> openim.admin.UnblockUserResp + 75, // 136: openim.admin.admin.SearchBlockUser:output_type -> openim.admin.SearchBlockUserResp + 78, // 137: openim.admin.admin.FindUserBlockInfo:output_type -> openim.admin.FindUserBlockInfoResp + 64, // 138: openim.admin.admin.CheckRegisterForbidden:output_type -> openim.admin.CheckRegisterForbiddenResp + 66, // 139: openim.admin.admin.CheckLoginForbidden:output_type -> openim.admin.CheckLoginForbiddenResp + 80, // 140: openim.admin.admin.CreateToken:output_type -> openim.admin.CreateTokenResp + 82, // 141: openim.admin.admin.ParseToken:output_type -> openim.admin.ParseTokenResp + 86, // 142: openim.admin.admin.AddApplet:output_type -> openim.admin.AddAppletResp + 88, // 143: openim.admin.admin.DelApplet:output_type -> openim.admin.DelAppletResp + 90, // 144: openim.admin.admin.UpdateApplet:output_type -> openim.admin.UpdateAppletResp + 92, // 145: openim.admin.admin.FindApplet:output_type -> openim.admin.FindAppletResp + 94, // 146: openim.admin.admin.SearchApplet:output_type -> openim.admin.SearchAppletResp + 100, // 147: openim.admin.admin.GetClientConfig:output_type -> openim.admin.GetClientConfigResp + 96, // 148: openim.admin.admin.SetClientConfig:output_type -> openim.admin.SetClientConfigResp + 98, // 149: openim.admin.admin.DelClientConfig:output_type -> openim.admin.DelClientConfigResp + 102, // 150: openim.admin.admin.GetUserToken:output_type -> openim.admin.GetUserTokenResp + 84, // 151: openim.admin.admin.InvalidateToken:output_type -> openim.admin.InvalidateTokenResp + 105, // 152: openim.admin.admin.LatestApplicationVersion:output_type -> openim.admin.LatestApplicationVersionResp + 107, // 153: openim.admin.admin.AddApplicationVersion:output_type -> openim.admin.AddApplicationVersionResp + 109, // 154: openim.admin.admin.UpdateApplicationVersion:output_type -> openim.admin.UpdateApplicationVersionResp + 111, // 155: openim.admin.admin.DeleteApplicationVersion:output_type -> openim.admin.DeleteApplicationVersionResp + 113, // 156: openim.admin.admin.PageApplicationVersion:output_type -> openim.admin.PageApplicationVersionResp + 105, // [105:157] is the sub-list for method output_type + 53, // [53:105] is the sub-list for method input_type + 53, // [53:53] is the sub-list for extension type_name + 53, // [53:53] is the sub-list for extension extendee + 0, // [0:53] is the sub-list for field type_name } func init() { file_admin_admin_proto_init() } @@ -7707,6 +8542,138 @@ func file_admin_admin_proto_init() { return nil } } + file_admin_admin_proto_msgTypes[103].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ApplicationVersion); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[104].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LatestApplicationVersionReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[105].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LatestApplicationVersionResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[106].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddApplicationVersionReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[107].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddApplicationVersionResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[108].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateApplicationVersionReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[109].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateApplicationVersionResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[110].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteApplicationVersionReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[111].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteApplicationVersionResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[112].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PageApplicationVersionReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_admin_proto_msgTypes[113].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PageApplicationVersionResp); 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{ @@ -7714,7 +8681,7 @@ func file_admin_admin_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_admin_admin_proto_rawDesc, NumEnums: 0, - NumMessages: 106, + NumMessages: 117, NumExtensions: 0, NumServices: 1, }, @@ -7799,6 +8766,11 @@ type AdminClient interface { GetUserToken(ctx context.Context, in *GetUserTokenReq, opts ...grpc.CallOption) (*GetUserTokenResp, error) // invalidate token InvalidateToken(ctx context.Context, in *InvalidateTokenReq, opts ...grpc.CallOption) (*InvalidateTokenResp, error) + LatestApplicationVersion(ctx context.Context, in *LatestApplicationVersionReq, opts ...grpc.CallOption) (*LatestApplicationVersionResp, error) + AddApplicationVersion(ctx context.Context, in *AddApplicationVersionReq, opts ...grpc.CallOption) (*AddApplicationVersionResp, error) + UpdateApplicationVersion(ctx context.Context, in *UpdateApplicationVersionReq, opts ...grpc.CallOption) (*UpdateApplicationVersionResp, error) + DeleteApplicationVersion(ctx context.Context, in *DeleteApplicationVersionReq, opts ...grpc.CallOption) (*DeleteApplicationVersionResp, error) + PageApplicationVersion(ctx context.Context, in *PageApplicationVersionReq, opts ...grpc.CallOption) (*PageApplicationVersionResp, error) } type adminClient struct { @@ -8232,6 +9204,51 @@ func (c *adminClient) InvalidateToken(ctx context.Context, in *InvalidateTokenRe return out, nil } +func (c *adminClient) LatestApplicationVersion(ctx context.Context, in *LatestApplicationVersionReq, opts ...grpc.CallOption) (*LatestApplicationVersionResp, error) { + out := new(LatestApplicationVersionResp) + err := c.cc.Invoke(ctx, "/openim.admin.admin/LatestApplicationVersion", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) AddApplicationVersion(ctx context.Context, in *AddApplicationVersionReq, opts ...grpc.CallOption) (*AddApplicationVersionResp, error) { + out := new(AddApplicationVersionResp) + err := c.cc.Invoke(ctx, "/openim.admin.admin/AddApplicationVersion", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) UpdateApplicationVersion(ctx context.Context, in *UpdateApplicationVersionReq, opts ...grpc.CallOption) (*UpdateApplicationVersionResp, error) { + out := new(UpdateApplicationVersionResp) + err := c.cc.Invoke(ctx, "/openim.admin.admin/UpdateApplicationVersion", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) DeleteApplicationVersion(ctx context.Context, in *DeleteApplicationVersionReq, opts ...grpc.CallOption) (*DeleteApplicationVersionResp, error) { + out := new(DeleteApplicationVersionResp) + err := c.cc.Invoke(ctx, "/openim.admin.admin/DeleteApplicationVersion", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminClient) PageApplicationVersion(ctx context.Context, in *PageApplicationVersionReq, opts ...grpc.CallOption) (*PageApplicationVersionResp, error) { + out := new(PageApplicationVersionResp) + err := c.cc.Invoke(ctx, "/openim.admin.admin/PageApplicationVersion", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // AdminServer is the server API for Admin service. type AdminServer interface { // Login @@ -8293,6 +9310,11 @@ type AdminServer interface { GetUserToken(context.Context, *GetUserTokenReq) (*GetUserTokenResp, error) // invalidate token InvalidateToken(context.Context, *InvalidateTokenReq) (*InvalidateTokenResp, error) + LatestApplicationVersion(context.Context, *LatestApplicationVersionReq) (*LatestApplicationVersionResp, error) + AddApplicationVersion(context.Context, *AddApplicationVersionReq) (*AddApplicationVersionResp, error) + UpdateApplicationVersion(context.Context, *UpdateApplicationVersionReq) (*UpdateApplicationVersionResp, error) + DeleteApplicationVersion(context.Context, *DeleteApplicationVersionReq) (*DeleteApplicationVersionResp, error) + PageApplicationVersion(context.Context, *PageApplicationVersionReq) (*PageApplicationVersionResp, error) } // UnimplementedAdminServer can be embedded to have forward compatible implementations. @@ -8440,6 +9462,21 @@ func (*UnimplementedAdminServer) GetUserToken(context.Context, *GetUserTokenReq) func (*UnimplementedAdminServer) InvalidateToken(context.Context, *InvalidateTokenReq) (*InvalidateTokenResp, error) { return nil, status.Errorf(codes.Unimplemented, "method InvalidateToken not implemented") } +func (*UnimplementedAdminServer) LatestApplicationVersion(context.Context, *LatestApplicationVersionReq) (*LatestApplicationVersionResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method LatestApplicationVersion not implemented") +} +func (*UnimplementedAdminServer) AddApplicationVersion(context.Context, *AddApplicationVersionReq) (*AddApplicationVersionResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddApplicationVersion not implemented") +} +func (*UnimplementedAdminServer) UpdateApplicationVersion(context.Context, *UpdateApplicationVersionReq) (*UpdateApplicationVersionResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateApplicationVersion not implemented") +} +func (*UnimplementedAdminServer) DeleteApplicationVersion(context.Context, *DeleteApplicationVersionReq) (*DeleteApplicationVersionResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteApplicationVersion not implemented") +} +func (*UnimplementedAdminServer) PageApplicationVersion(context.Context, *PageApplicationVersionReq) (*PageApplicationVersionResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method PageApplicationVersion not implemented") +} func RegisterAdminServer(s *grpc.Server, srv AdminServer) { s.RegisterService(&_Admin_serviceDesc, srv) @@ -9291,6 +10328,96 @@ func _Admin_InvalidateToken_Handler(srv interface{}, ctx context.Context, dec fu return interceptor(ctx, in, info, handler) } +func _Admin_LatestApplicationVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(LatestApplicationVersionReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).LatestApplicationVersion(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/openim.admin.admin/LatestApplicationVersion", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).LatestApplicationVersion(ctx, req.(*LatestApplicationVersionReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_AddApplicationVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddApplicationVersionReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).AddApplicationVersion(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/openim.admin.admin/AddApplicationVersion", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).AddApplicationVersion(ctx, req.(*AddApplicationVersionReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_UpdateApplicationVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateApplicationVersionReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).UpdateApplicationVersion(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/openim.admin.admin/UpdateApplicationVersion", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).UpdateApplicationVersion(ctx, req.(*UpdateApplicationVersionReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_DeleteApplicationVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteApplicationVersionReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).DeleteApplicationVersion(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/openim.admin.admin/DeleteApplicationVersion", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).DeleteApplicationVersion(ctx, req.(*DeleteApplicationVersionReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Admin_PageApplicationVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PageApplicationVersionReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServer).PageApplicationVersion(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/openim.admin.admin/PageApplicationVersion", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServer).PageApplicationVersion(ctx, req.(*PageApplicationVersionReq)) + } + return interceptor(ctx, in, info, handler) +} + var _Admin_serviceDesc = grpc.ServiceDesc{ ServiceName: "openim.admin.admin", HandlerType: (*AdminServer)(nil), @@ -9483,6 +10610,26 @@ var _Admin_serviceDesc = grpc.ServiceDesc{ MethodName: "InvalidateToken", Handler: _Admin_InvalidateToken_Handler, }, + { + MethodName: "LatestApplicationVersion", + Handler: _Admin_LatestApplicationVersion_Handler, + }, + { + MethodName: "AddApplicationVersion", + Handler: _Admin_AddApplicationVersion_Handler, + }, + { + MethodName: "UpdateApplicationVersion", + Handler: _Admin_UpdateApplicationVersion_Handler, + }, + { + MethodName: "DeleteApplicationVersion", + Handler: _Admin_DeleteApplicationVersion_Handler, + }, + { + MethodName: "PageApplicationVersion", + Handler: _Admin_PageApplicationVersion_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "admin/admin.proto", diff --git a/pkg/protocol/admin/admin.proto b/pkg/protocol/admin/admin.proto index 2c4ee995a..86063aa03 100644 --- a/pkg/protocol/admin/admin.proto +++ b/pkg/protocol/admin/admin.proto @@ -485,6 +485,76 @@ message GetUserTokenResp { map tokensMap = 1; } + +message ApplicationVersion { + string id = 1; + string platform = 2; + string version = 3; + string url = 4; + string text = 5; + bool force = 6; + bool latest = 7; + bool hot = 8; + int64 createTime = 9; +} + +message LatestApplicationVersionReq { + string platform = 2; + string version = 3; +} + +message LatestApplicationVersionResp { + ApplicationVersion version = 1; +} + +message AddApplicationVersionReq { + string platform = 1; + string version = 2; + string url = 3; + string text = 4; + bool force = 5; + bool latest = 6; + bool hot = 7; +} + +message AddApplicationVersionResp { + +} + +message UpdateApplicationVersionReq { + string id = 1; + openim.protobuf.StringValue platform = 2; + openim.protobuf.StringValue version = 3; + openim.protobuf.StringValue url = 4; + openim.protobuf.StringValue text = 5; + openim.protobuf.BoolValue force = 6; + openim.protobuf.BoolValue latest = 7; + openim.protobuf.BoolValue hot = 8; +} + +message UpdateApplicationVersionResp { + +} + +message DeleteApplicationVersionReq { + repeated string id = 1; +} + +message DeleteApplicationVersionResp { + +} + +message PageApplicationVersionReq { + repeated string platform = 1; + openim.sdkws.RequestPagination pagination = 2; +} + +message PageApplicationVersionResp { + int64 total = 1; + repeated ApplicationVersion versions = 2; +} + + service admin { // Login rpc Login(LoginReq) returns (LoginResp); @@ -557,4 +627,10 @@ service admin { // invalidate token rpc InvalidateToken(InvalidateTokenReq) returns (InvalidateTokenResp); + + rpc LatestApplicationVersion(LatestApplicationVersionReq) returns (LatestApplicationVersionResp); + rpc AddApplicationVersion(AddApplicationVersionReq) returns (AddApplicationVersionResp); + rpc UpdateApplicationVersion(UpdateApplicationVersionReq) returns (UpdateApplicationVersionResp); + rpc DeleteApplicationVersion(DeleteApplicationVersionReq) returns (DeleteApplicationVersionResp); + rpc PageApplicationVersion(PageApplicationVersionReq) returns (PageApplicationVersionResp); } From a8f2a3d9717123782e83a58233e06da329595776 Mon Sep 17 00:00:00 2001 From: icey-yu <119291641+icey-yu@users.noreply.github.com> Date: Thu, 7 Nov 2024 11:32:12 +0800 Subject: [PATCH 17/36] fix: admin token cache (#613) * fix: admin token cache * fix: admin token cache --- internal/api/admin/admin.go | 10 +++---- internal/api/chat/chat.go | 16 ++--------- pkg/common/imapi/caller.go | 37 +++++++++++++++++--------- pkg/common/tokenverify/token_verify.go | 17 +----------- tools/check-component/main.go | 2 +- 5 files changed, 34 insertions(+), 48 deletions(-) diff --git a/internal/api/admin/admin.go b/internal/api/admin/admin.go index e4f34b906..b3b3ee395 100644 --- a/internal/api/admin/admin.go +++ b/internal/api/admin/admin.go @@ -113,7 +113,7 @@ func (o *Api) AdminUpdateInfo(c *gin.Context) { } imAdminUserID := o.GetDefaultIMAdminUserID() - imToken, err := o.imApiCaller.GetAdminToken(c, imAdminUserID) + imToken, err := o.imApiCaller.GetAdminTokenCache(c, imAdminUserID) if err != nil { log.ZError(c, "AdminUpdateInfo ImAdminTokenWithDefaultAdmin", err, "imAdminUserID", imAdminUserID) return @@ -193,7 +193,7 @@ func (o *Api) AddDefaultGroup(c *gin.Context) { apiresp.GinError(c, err) return } - imToken, err := o.imApiCaller.GetAdminToken(c, o.GetDefaultIMAdminUserID()) + imToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) if err != nil { apiresp.GinError(c, err) return @@ -241,7 +241,7 @@ func (o *Api) SearchDefaultGroup(c *gin.Context) { Groups: make([]*sdkws.GroupInfo, 0, len(searchResp.GroupIDs)), } if len(searchResp.GroupIDs) > 0 { - imToken, err := o.imApiCaller.GetAdminToken(c, o.GetDefaultIMAdminUserID()) + imToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) if err != nil { apiresp.GinError(c, err) return @@ -323,7 +323,7 @@ func (o *Api) BlockUser(c *gin.Context) { apiresp.GinError(c, err) return } - imToken, err := o.imApiCaller.GetAdminToken(c, o.GetDefaultIMAdminUserID()) + imToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) if err != nil { apiresp.GinError(c, err) return @@ -382,7 +382,7 @@ func (o *Api) NewUserCount(c *gin.Context) { apiresp.GinError(c, err) return } - imToken, err := o.imApiCaller.GetAdminToken(c, o.GetDefaultIMAdminUserID()) + imToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) if err != nil { apiresp.GinError(c, err) return diff --git a/internal/api/chat/chat.go b/internal/api/chat/chat.go index d6d8d51e1..e61978ed3 100644 --- a/internal/api/chat/chat.go +++ b/internal/api/chat/chat.go @@ -22,7 +22,6 @@ import ( "github.com/gin-gonic/gin" "github.com/openimsdk/chat/pkg/common/apistruct" - "github.com/openimsdk/chat/pkg/common/constant" "github.com/openimsdk/chat/pkg/common/imapi" "github.com/openimsdk/chat/pkg/common/mctx" "github.com/openimsdk/chat/pkg/protocol/admin" @@ -235,20 +234,9 @@ func (o *Api) UpdateUserInfo(c *gin.Context) { apiresp.GinError(c, err) return } - opUserType, err := mctx.GetUserType(c) - if err != nil { - apiresp.GinError(c, err) - return - } + var imToken string - if opUserType == constant.NormalUser { - imToken, err = o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) - } else if opUserType == constant.AdminUser { - imToken, err = o.imApiCaller.GetAdminToken(c, o.GetDefaultIMAdminUserID()) - } else { - apiresp.GinError(c, errs.ErrArgs.WrapMsg("opUserType unknown")) - return - } + imToken, err = o.imApiCaller.ImAdminTokenWithDefaultAdmin(c) if err != nil { apiresp.GinError(c, err) return diff --git a/pkg/common/imapi/caller.go b/pkg/common/imapi/caller.go index 88f8f9141..3ebee9213 100644 --- a/pkg/common/imapi/caller.go +++ b/pkg/common/imapi/caller.go @@ -20,7 +20,7 @@ type CallerInterface interface { ImAdminTokenWithDefaultAdmin(ctx context.Context) (string, error) ImportFriend(ctx context.Context, ownerUserID string, friendUserID []string) error GetUserToken(ctx context.Context, userID string, platform int32) (string, error) - GetAdminToken(ctx context.Context, userID string) (string, error) + GetAdminTokenCache(ctx context.Context, userID string) (string, error) InviteToGroup(ctx context.Context, userID string, groupIDs []string) error UpdateUserInfo(ctx context.Context, userID string, nickName string, faceURL string) error ForceOffLine(ctx context.Context, userID string) error @@ -31,13 +31,17 @@ type CallerInterface interface { AccountCheckSingle(ctx context.Context, userID string) (bool, error) } +type authToken struct { + token string + timeout time.Time +} + type Caller struct { imApi string imSecret string defaultIMUserID string - token string - timeout time.Time - lock sync.Mutex + tokenCache map[string]*authToken + lock sync.RWMutex } func New(imApi string, imSecret string, defaultIMUserID string) CallerInterface { @@ -45,6 +49,8 @@ func New(imApi string, imSecret string, defaultIMUserID string) CallerInterface imApi: imApi, imSecret: imSecret, defaultIMUserID: defaultIMUserID, + tokenCache: make(map[string]*authToken), + lock: sync.RWMutex{}, } } @@ -60,25 +66,32 @@ func (c *Caller) ImportFriend(ctx context.Context, ownerUserID string, friendUse } func (c *Caller) ImAdminTokenWithDefaultAdmin(ctx context.Context) (string, error) { - if c.token == "" || c.timeout.Before(time.Now()) { + return c.GetAdminTokenCache(ctx, c.defaultIMUserID) +} + +func (c *Caller) GetAdminTokenCache(ctx context.Context, userID string) (string, error) { + c.lock.RLock() + t, ok := c.tokenCache[userID] + c.lock.RUnlock() + if !ok || t.timeout.Before(time.Now()) { c.lock.Lock() - if c.token == "" || c.timeout.Before(time.Now()) { - userID := c.defaultIMUserID - token, err := c.GetAdminToken(ctx, userID) + t, ok = c.tokenCache[userID] + if !ok || t.timeout.Before(time.Now()) { + token, err := c.getAdminTokenServer(ctx, userID) if err != nil { log.ZError(ctx, "get im admin token", err, "userID", userID) return "", err } log.ZDebug(ctx, "get im admin token", "userID", userID) - c.token = token - c.timeout = time.Now().Add(time.Minute * 5) + t = &authToken{token: token, timeout: time.Now().Add(time.Minute * 5)} + c.tokenCache[userID] = t } c.lock.Unlock() } - return c.token, nil + return t.token, nil } -func (c *Caller) GetAdminToken(ctx context.Context, userID string) (string, error) { +func (c *Caller) getAdminTokenServer(ctx context.Context, userID string) (string, error) { resp, err := getAdminToken.Call(ctx, c.imApi, &auth.GetAdminTokenReq{ Secret: c.imSecret, UserID: userID, diff --git a/pkg/common/tokenverify/token_verify.go b/pkg/common/tokenverify/token_verify.go index 59521873f..f53cd5aee 100644 --- a/pkg/common/tokenverify/token_verify.go +++ b/pkg/common/tokenverify/token_verify.go @@ -109,22 +109,7 @@ func (t *Token) GetToken(token string) (string, int32, error) { return userID, userType, nil } -func (t *Token) GetExpire(token string) time.Time { - val, err := jwt.ParseWithClaims(token, &claims{}, t.secret()) - if err != nil { - return time.Time{} - } - c, ok := val.Claims.(*claims) - if !ok { - return time.Time{} - } - if c.ExpiresAt == nil { - return time.Time{} - } - return c.ExpiresAt.Time -} - -//func (t *Token) GetAdminToken(token string) (string, error) { +//func (t *Token) GetAdminTokenCache(token string) (string, error) { // userID, userType, err := getToken(token) // if err != nil { // return "", err diff --git a/tools/check-component/main.go b/tools/check-component/main.go index ab7676a16..f3f2dd25f 100644 --- a/tools/check-component/main.go +++ b/tools/check-component/main.go @@ -57,7 +57,7 @@ func CheckRedis(ctx context.Context, config *config.Redis) error { func CheckOpenIM(ctx context.Context, apiURL, secret, adminUserID string) error { imAPI := imapi.New(apiURL, secret, adminUserID) - _, err := imAPI.GetAdminToken(mcontext.SetOperationID(ctx, "CheckOpenIM"+idutil.OperationIDGenerator()), adminUserID) + _, err := imAPI.GetAdminTokenCache(mcontext.SetOperationID(ctx, "CheckOpenIM"+idutil.OperationIDGenerator()), adminUserID) return err } From d4f229fdb033bc921285b0b62c74cbe7a1b77cd6 Mon Sep 17 00:00:00 2001 From: Monet Lee Date: Mon, 25 Nov 2024 12:09:16 +0800 Subject: [PATCH 18/36] fix: solve merge error. --- .../workflows/remove-unused-labels copy.yml | 74 ------------------- go.mod | 6 +- pkg/common/db/database/admin.go | 6 +- pkg/common/tokenverify/token_verify.go | 15 ++++ 4 files changed, 23 insertions(+), 78 deletions(-) delete mode 100644 .github/workflows/remove-unused-labels copy.yml diff --git a/.github/workflows/remove-unused-labels copy.yml b/.github/workflows/remove-unused-labels copy.yml deleted file mode 100644 index ab80b1f96..000000000 --- a/.github/workflows/remove-unused-labels copy.yml +++ /dev/null @@ -1,74 +0,0 @@ -name: Remove Unused Labels -on: - workflow_dispatch: - -jobs: - cleanup: - runs-on: ubuntu-latest - permissions: - issues: write - pull-requests: write - contents: read - steps: - - name: Checkout Repository - uses: actions/checkout@v4 - - - name: Fetch All Issues and PRs - id: fetch_issues_prs - uses: actions/github-script@v7.0.1 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const issues = await github.paginate(github.rest.issues.listForRepo, { - owner: context.repo.owner, - repo: context.repo.repo, - state: 'all', - per_page: 100 - }); - - const labelsInUse = new Set(); - issues.forEach(issue => { - issue.labels.forEach(label => { - labelsInUse.add(label.name); - }); - }); - - return JSON.stringify(Array.from(labelsInUse)); - result-encoding: string - - - name: Fetch All Labels - id: fetch_labels - uses: actions/github-script@v7.0.1 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const labels = await github.paginate(github.rest.issues.listLabelsForRepo, { - owner: context.repo.owner, - repo: context.repo.repo, - per_page: 100 - }); - - return JSON.stringify(labels.map(label => label.name)); - result-encoding: string - - - name: Remove Unused Labels - uses: actions/github-script@v7.0.1 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const labelsInUse = new Set(JSON.parse(process.env.LABELS_IN_USE)); - const allLabels = JSON.parse(process.env.ALL_LABELS); - - const unusedLabels = allLabels.filter(label => !labelsInUse.has(label)); - - for (const label of unusedLabels) { - await github.rest.issues.deleteLabel({ - owner: context.repo.owner, - repo: context.repo.repo, - name: label - }); - console.log(`Deleted label: ${label}`); - } - env: - LABELS_IN_USE: ${{ steps.fetch_issues_prs.outputs.result }} - ALL_LABELS: ${{ steps.fetch_labels.outputs.result }} diff --git a/go.mod b/go.mod index 415298ac2..830aacac6 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/openimsdk/chat -go 1.21 +go 1.21.2 + +toolchain go1.23.2 require ( github.com/gin-gonic/gin v1.9.1 @@ -11,7 +13,7 @@ require ( github.com/pkg/errors v0.9.1 // indirect google.golang.org/grpc v1.62.1 google.golang.org/protobuf v1.33.0 - gopkg.in/yaml.v3 v3.0.1 + gopkg.in/yaml.v3 v3.0.1 // indirect gorm.io/gorm v1.25.8 ) diff --git a/pkg/common/db/database/admin.go b/pkg/common/db/database/admin.go index 527a32d65..74b9ee4db 100644 --- a/pkg/common/db/database/admin.go +++ b/pkg/common/db/database/admin.go @@ -16,10 +16,12 @@ package database import ( "context" - "go.mongodb.org/mongo-driver/bson/primitive" "time" + "go.mongodb.org/mongo-driver/bson/primitive" + "github.com/openimsdk/chat/pkg/common/db/cache" + "github.com/openimsdk/chat/pkg/common/tokenverify" "github.com/openimsdk/tools/db/mongoutil" "github.com/openimsdk/tools/db/pagination" "github.com/openimsdk/tools/db/tx" @@ -138,7 +140,7 @@ func NewAdminDatabase(cli *mongoutil.Client, rdb redis.UniversalClient, token *t applet: applet, clientConfig: clientConfig, application: application, - cache: cache.NewTokenInterface(rdb), + cache: cache.NewTokenInterface(rdb, token), }, nil } diff --git a/pkg/common/tokenverify/token_verify.go b/pkg/common/tokenverify/token_verify.go index f53cd5aee..7cf68d8a3 100644 --- a/pkg/common/tokenverify/token_verify.go +++ b/pkg/common/tokenverify/token_verify.go @@ -109,6 +109,21 @@ func (t *Token) GetToken(token string) (string, int32, error) { return userID, userType, nil } +func (t *Token) GetExpire(token string) time.Time { + val, err := jwt.ParseWithClaims(token, &claims{}, t.secret()) + if err != nil { + return time.Time{} + } + c, ok := val.Claims.(*claims) + if !ok { + return time.Time{} + } + if c.ExpiresAt == nil { + return time.Time{} + } + return c.ExpiresAt.Time +} + //func (t *Token) GetAdminTokenCache(token string) (string, error) { // userID, userType, err := getToken(token) // if err != nil { From 762e98020db95c6d35294f3d378d115708d8e45d Mon Sep 17 00:00:00 2001 From: Monet Lee Date: Mon, 16 Dec 2024 18:07:09 +0800 Subject: [PATCH 19/36] build: improve module image build and kubernetes adapt. (#616) * build: improve image generate. * build: improve loadConfig and discovery by kubernetes. * move version path. * move build iamges foler name. * build: create release images. * update go pkg and import. * update mongo field. * fix: improve DialOption in Discovery. * revert log input. --- .../build-and-release-services-images.yml | 91 ++++++++++++++++ build/images/api-admin/Dockerfile | 48 --------- build/images/api-chat/Dockerfile | 48 --------- build/images/openim-admin-api/Dockerfile | 36 +++++++ build/images/openim-admin-rpc/Dockerfile | 36 +++++++ build/images/openim-chat-api/Dockerfile | 36 +++++++ build/images/openim-chat-rpc/Dockerfile | 36 +++++++ build/images/rpc-admin/Dockerfile | 48 --------- build/images/rpc-chat/Dockerfile | 48 --------- config/discovery.yml | 10 +- config/log.yml | 2 +- config/mongodb.yml | 6 +- config/share.yml | 6 -- go.mod | 52 ++++++--- go.sum | 100 ++++++++++++++---- internal/api/admin/start.go | 13 ++- internal/api/chat/start.go | 11 +- internal/rpc/admin/start.go | 7 +- internal/rpc/chat/start.go | 2 +- pkg/common/cmd/admin_rpc.go | 3 +- pkg/common/cmd/chat_rpc.go | 3 +- pkg/common/cmd/root.go | 16 +-- pkg/common/config/config.go | 26 +++-- pkg/common/config/load.go | 21 +++- pkg/common/constant/constant.go | 6 ++ pkg/common/kdisc/discoveryregister.go | 28 +++-- pkg/common/kdisc/zookeeper/doc.go | 15 --- pkg/common/kdisc/zookeeper/zookeeper.go | 44 -------- pkg/common/startrpc/start.go | 14 ++- tools/attribute-to-credential/main.go | 9 +- tools/check-component/main.go | 21 ++-- version/{version => }/version | 0 version/{version => }/version.go | 0 33 files changed, 476 insertions(+), 366 deletions(-) create mode 100644 .github/workflows/build-and-release-services-images.yml delete mode 100644 build/images/api-admin/Dockerfile delete mode 100644 build/images/api-chat/Dockerfile create mode 100644 build/images/openim-admin-api/Dockerfile create mode 100644 build/images/openim-admin-rpc/Dockerfile create mode 100644 build/images/openim-chat-api/Dockerfile create mode 100644 build/images/openim-chat-rpc/Dockerfile delete mode 100644 build/images/rpc-admin/Dockerfile delete mode 100644 build/images/rpc-chat/Dockerfile delete mode 100644 pkg/common/kdisc/zookeeper/doc.go delete mode 100644 pkg/common/kdisc/zookeeper/zookeeper.go rename version/{version => }/version (100%) rename version/{version => }/version.go (100%) diff --git a/.github/workflows/build-and-release-services-images.yml b/.github/workflows/build-and-release-services-images.yml new file mode 100644 index 000000000..d53fd2142 --- /dev/null +++ b/.github/workflows/build-and-release-services-images.yml @@ -0,0 +1,91 @@ +name: Build and release services Images + +on: + push: + branches: + - release-* + release: + types: [published] + workflow_dispatch: + inputs: + tag: + description: "Tag version to be used for Docker image" + required: true + default: "v3.8.3" + +jobs: + build-and-push: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Log in to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Log in to Aliyun Container Registry + uses: docker/login-action@v2 + with: + registry: registry.cn-hangzhou.aliyuncs.com + username: ${{ secrets.ALIREGISTRY_USERNAME }} + password: ${{ secrets.ALIREGISTRY_TOKEN }} + + - name: Extract metadata for Docker (tags, labels) + id: meta + uses: docker/metadata-action@v5 + with: + tags: | + type=ref,event=tag + type=schedule + type=ref,event=branch + type=semver,pattern={{version}} + type=semver,pattern=v{{version}} + # type=semver,pattern={{major}}.{{minor}} + type=semver,pattern=release-{{raw}} + type=sha + type=raw,value=${{ github.event.inputs.tag }} + + - name: Build and push Docker images + run: | + ROOT_DIR="build/images" + for dir in "$ROOT_DIR"/*/; do + # Find Dockerfile or *.dockerfile in a case-insensitive manner + dockerfile=$(find "$dir" -maxdepth 1 -type f \( -iname 'dockerfile' -o -iname '*.dockerfile' \) | head -n 1) + + if [ -n "$dockerfile" ] && [ -f "$dockerfile" ]; then + IMAGE_NAME=$(basename "$dir") + echo "Building Docker image for $IMAGE_NAME with tags:" + + # Initialize tag arguments + tag_args=() + + # Read each tag and append --tag arguments + while IFS= read -r tag; do + tag_args+=(--tag "${{ secrets.DOCKER_USERNAME }}/$IMAGE_NAME:$tag") + tag_args+=(--tag "ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME:$tag") + tag_args+=(--tag "registry.cn-hangzhou.aliyuncs.com/openimsdk/$IMAGE_NAME:$tag") + done <<< "${{ steps.meta.outputs.tags }}" + + # Build and push the Docker image with all tags + docker buildx build --platform linux/amd64,linux/arm64 \ + --file "$dockerfile" \ + "${tag_args[@]}" \ + --push "$dir" + else + echo "No valid Dockerfile found in $dir" + fi + done \ No newline at end of file diff --git a/build/images/api-admin/Dockerfile b/build/images/api-admin/Dockerfile deleted file mode 100644 index 6da6be2bc..000000000 --- a/build/images/api-admin/Dockerfile +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -# OpenIM base image: https://github.com/openim-sigs/openim-base-image - -# Set go mod installation source and proxy - -ARG GOARCH -ARG GOOS - -FROM golang:1.21 AS builder - -ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.io,direct - -WORKDIR /openim/openim-chat - -ENV GO111MODULE=$GO111MODULE -ENV GOPROXY=$GOPROXY - -COPY go.mod go.sum ./ -RUN go mod download - -COPY . . - -RUN make build BINS=admin-api - -RUN cp /openim/openim-chat/_output/bin/platforms/$(go env GOOS)/$(go env GOARCH)/admin-api /usr/bin/admin-api - - -FROM ghcr.io/openim-sigs/openim-bash-image:latest - -WORKDIR ${CHAT_WORKDIR} - -COPY --from=builder /usr/bin/admin-api ./bin/admin-api - -ENTRYPOINT ["./bin/admin-api"] \ No newline at end of file diff --git a/build/images/api-chat/Dockerfile b/build/images/api-chat/Dockerfile deleted file mode 100644 index 3fb734fc9..000000000 --- a/build/images/api-chat/Dockerfile +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -# OpenIM base image: https://github.com/openim-sigs/openim-base-image - -# Set go mod installation source and proxy - -ARG GOARCH -ARG GOOS - -FROM golang:1.21 AS builder - -ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.io,direct - -WORKDIR /openim/openim-chat - -ENV GO111MODULE=$GO111MODULE -ENV GOPROXY=$GOPROXY - -COPY go.mod go.sum ./ -RUN go mod download - -COPY . . - -RUN make build BINS=chat-api - -RUN cp /openim/openim-chat/_output/bin/platforms/$(go env GOOS)/$(go env GOARCH)/chat-api /usr/bin/chat-api - - -FROM ghcr.io/openim-sigs/openim-bash-image:latest - -WORKDIR ${CHAT_WORKDIR} - -COPY --from=builder /usr/bin/chat-api ./bin/chat-api - -ENTRYPOINT ["./bin/chat-api"] \ No newline at end of file diff --git a/build/images/openim-admin-api/Dockerfile b/build/images/openim-admin-api/Dockerfile new file mode 100644 index 000000000..5f74d61a7 --- /dev/null +++ b/build/images/openim-admin-api/Dockerfile @@ -0,0 +1,36 @@ +# Use Go 1.22 Alpine as the base image for building the application +FROM golang:1.22-alpine AS builder + +# Define the base directory for the application as an environment variable +ENV CHAT_DIR=/openim-chat + +# Set the working directory inside the container based on the environment variable +WORKDIR $CHAT_DIR + +# Set the Go proxy to improve dependency resolution speed +#ENV GOPROXY=https://goproxy.io,direct + +# Copy all files from the current directory into the container +COPY . . + +RUN go mod tidy + +RUN go build -o _output/admin-api ./cmd/api/admin-api + +# Using Alpine Linux for the final image +FROM alpine:latest + +# Install necessary packages, such as bash +RUN apk add --no-cache bash + +# Set the environment and work directory +ENV CHAT_DIR=/openim-chat +WORKDIR $CHAT_DIR + + +# Copy the compiled binaries and mage from the builder image to the final image +COPY --from=builder $CHAT_DIR/_output $CHAT_DIR/_output +COPY --from=builder $CHAT_DIR/config $CHAT_DIR/config + +# Set the command to run when the container starts +ENTRYPOINT ["sh", "-c", "_output/admin-api"] \ No newline at end of file diff --git a/build/images/openim-admin-rpc/Dockerfile b/build/images/openim-admin-rpc/Dockerfile new file mode 100644 index 000000000..4f1ae7edd --- /dev/null +++ b/build/images/openim-admin-rpc/Dockerfile @@ -0,0 +1,36 @@ +# Use Go 1.22 Alpine as the base image for building the application +FROM golang:1.22-alpine AS builder + +# Define the base directory for the application as an environment variable +ENV CHAT_DIR=/openim-chat + +# Set the working directory inside the container based on the environment variable +WORKDIR $CHAT_DIR + +# Set the Go proxy to improve dependency resolution speed +#ENV GOPROXY=https://goproxy.io,direct + +# Copy all files from the current directory into the container +COPY . . + +RUN go mod tidy + +RUN go build -o _output/admin-rpc ./cmd/rpc/admin-rpc + +# Using Alpine Linux for the final image +FROM alpine:latest + +# Install necessary packages, such as bash +RUN apk add --no-cache bash + +# Set the environment and work directory +ENV CHAT_DIR=/openim-chat +WORKDIR $CHAT_DIR + + +# Copy the compiled binaries and mage from the builder image to the final image +COPY --from=builder $CHAT_DIR/_output $CHAT_DIR/_output +COPY --from=builder $CHAT_DIR/config $CHAT_DIR/config + +# Set the command to run when the container starts +ENTRYPOINT ["sh", "-c", "_output/admin-rpc"] \ No newline at end of file diff --git a/build/images/openim-chat-api/Dockerfile b/build/images/openim-chat-api/Dockerfile new file mode 100644 index 000000000..4b03ebd6b --- /dev/null +++ b/build/images/openim-chat-api/Dockerfile @@ -0,0 +1,36 @@ +# Use Go 1.22 Alpine as the base image for building the application +FROM golang:1.22-alpine AS builder + +# Define the base directory for the application as an environment variable +ENV CHAT_DIR=/openim-chat + +# Set the working directory inside the container based on the environment variable +WORKDIR $CHAT_DIR + +# Set the Go proxy to improve dependency resolution speed +#ENV GOPROXY=https://goproxy.io,direct + +# Copy all files from the current directory into the container +COPY . . + +RUN go mod tidy + +RUN go build -o _output/chat-api ./cmd/api/chat-api + +# Using Alpine Linux for the final image +FROM alpine:latest + +# Install necessary packages, such as bash +RUN apk add --no-cache bash + +# Set the environment and work directory +ENV CHAT_DIR=/openim-chat +WORKDIR $CHAT_DIR + + +# Copy the compiled binaries and mage from the builder image to the final image +COPY --from=builder $CHAT_DIR/_output $CHAT_DIR/_output +COPY --from=builder $CHAT_DIR/config $CHAT_DIR/config + +# Set the command to run when the container starts +ENTRYPOINT ["sh", "-c", "_output/chat-api"] \ No newline at end of file diff --git a/build/images/openim-chat-rpc/Dockerfile b/build/images/openim-chat-rpc/Dockerfile new file mode 100644 index 000000000..e24e094db --- /dev/null +++ b/build/images/openim-chat-rpc/Dockerfile @@ -0,0 +1,36 @@ +# Use Go 1.22 Alpine as the base image for building the application +FROM golang:1.22-alpine AS builder + +# Define the base directory for the application as an environment variable +ENV CHAT_DIR=/openim-chat + +# Set the working directory inside the container based on the environment variable +WORKDIR $CHAT_DIR + +# Set the Go proxy to improve dependency resolution speed +#ENV GOPROXY=https://goproxy.io,direct + +# Copy all files from the current directory into the container +COPY . . + +RUN go mod tidy + +RUN go build -o _output/chat-rpc ./cmd/rpc/chat-rpc + +# Using Alpine Linux for the final image +FROM alpine:latest + +# Install necessary packages, such as bash +RUN apk add --no-cache bash + +# Set the environment and work directory +ENV CHAT_DIR=/openim-chat +WORKDIR $CHAT_DIR + + +# Copy the compiled binaries and mage from the builder image to the final image +COPY --from=builder $CHAT_DIR/_output $CHAT_DIR/_output +COPY --from=builder $CHAT_DIR/config $CHAT_DIR/config + +# Set the command to run when the container starts +ENTRYPOINT ["sh", "-c", "_output/chat-rpc"] \ No newline at end of file diff --git a/build/images/rpc-admin/Dockerfile b/build/images/rpc-admin/Dockerfile deleted file mode 100644 index 639d6c8d3..000000000 --- a/build/images/rpc-admin/Dockerfile +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -# OpenIM base image: https://github.com/openim-sigs/openim-base-image - -# Set go mod installation source and proxy - -ARG GOARCH -ARG GOOS - -FROM golang:1.21 AS builder - -ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.io,direct - -WORKDIR /openim/openim-chat - -ENV GO111MODULE=$GO111MODULE -ENV GOPROXY=$GOPROXY - -COPY go.mod go.sum ./ -RUN go mod download - -COPY . . - -RUN make build BINS=admin-rpc - -RUN cp /openim/openim-chat/_output/bin/platforms/$(go env GOOS)/$(go env GOARCH)/admin-rpc /usr/bin/admin-rpc - - -FROM ghcr.io/openim-sigs/openim-bash-image:latest - -WORKDIR ${CHAT_WORKDIR} - -COPY --from=builder /usr/bin/admin-rpc ./bin/admin-rpc - -ENTRYPOINT ["./bin/admin-rpc"] \ No newline at end of file diff --git a/build/images/rpc-chat/Dockerfile b/build/images/rpc-chat/Dockerfile deleted file mode 100644 index 4c602cf11..000000000 --- a/build/images/rpc-chat/Dockerfile +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -# OpenIM base image: https://github.com/openim-sigs/openim-base-image - -# Set go mod installation source and proxy - -ARG GOARCH -ARG GOOS - -FROM golang:1.21 AS builder - -ARG GO111MODULE=on -ARG GOPROXY=https://goproxy.io,direct - -WORKDIR /openim/openim-chat - -ENV GO111MODULE=$GO111MODULE -ENV GOPROXY=$GOPROXY - -COPY go.mod go.sum ./ -RUN go mod download - -COPY . . - -RUN make build BINS=chat-rpc - -RUN cp /openim/openim-chat/_output/bin/platforms/$(go env GOOS)/$(go env GOARCH)/chat-rpc /usr/bin/chat-rpc - - -FROM ghcr.io/openim-sigs/openim-bash-image:latest - -WORKDIR ${CHAT_WORKDIR} - -COPY --from=builder /usr/bin/chat-rpc ./bin/chat-rpc - -ENTRYPOINT ["./bin/chat-rpc"] \ No newline at end of file diff --git a/config/discovery.yml b/config/discovery.yml index 3d96ff9b6..1c34af784 100644 --- a/config/discovery.yml +++ b/config/discovery.yml @@ -5,9 +5,9 @@ etcd: username: '' password: '' -zookeeper: - schema: openim - address: [ localhost:12181 ] - username: '' - password: '' +kubernetes: + namespace: default +rpcService: + chat: chat-rpc-service + admin: admin-rpc-service diff --git a/config/log.yml b/config/log.yml index 8620af611..b8564e8b3 100644 --- a/config/log.yml +++ b/config/log.yml @@ -11,4 +11,4 @@ isStdout: false # Whether to log in JSON format, default is acceptable isJson: false # output simplify log when KeyAndValues's value len is bigger than 50 in rpc method log -isSimplify: true \ No newline at end of file +isSimplify: true diff --git a/config/mongodb.yml b/config/mongodb.yml index 98f5694e4..d3553ed8a 100644 --- a/config/mongodb.yml +++ b/config/mongodb.yml @@ -1,13 +1,15 @@ # URI for database connection, leave empty if using address and credential settings directly -uri: '' +uri: "" # List of MongoDB server addresses -address: [ localhost:37017 ] +address: [localhost:37017] # Name of the database database: openim_v3 # Username for database authentication username: openIM # Password for database authentication password: openIM123 +# Authentication source for database authentication, if use root user, set it to admin +authSource: openim_v3 # Maximum number of connections in the connection pool maxPoolSize: 100 # Maximum number of retry attempts for a failed database connection diff --git a/config/share.yml b/config/share.yml index 6b1bab178..907b569ca 100644 --- a/config/share.yml +++ b/config/share.yml @@ -1,8 +1,3 @@ -env: zookeeper -rpcRegisterName: - chat: chat - admin: admin - openIM: # OpenIM API address apiURL: http://127.0.0.1:10002 @@ -14,4 +9,3 @@ openIM: chatAdmin: # Default username and password for the admin - "chatAdmin" - diff --git a/go.mod b/go.mod index 830aacac6..71433ed82 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/openimsdk/chat -go 1.21.2 +go 1.22.0 toolchain go1.23.2 @@ -10,9 +10,9 @@ require ( github.com/golang/protobuf v1.5.4 // indirect github.com/google/uuid v1.6.0 github.com/jinzhu/copier v0.4.0 // indirect - github.com/pkg/errors v0.9.1 // indirect + github.com/pkg/errors v0.9.1 google.golang.org/grpc v1.62.1 - google.golang.org/protobuf v1.33.0 + google.golang.org/protobuf v1.34.2 gopkg.in/yaml.v3 v3.0.1 // indirect gorm.io/gorm v1.25.8 ) @@ -28,13 +28,18 @@ require ( github.com/mitchellh/mapstructure v1.5.0 github.com/openimsdk/gomake v0.0.14-alpha.5 github.com/openimsdk/protocol v0.0.72 - github.com/openimsdk/tools v0.0.50-alpha.20 + github.com/openimsdk/tools v0.0.50-alpha.56 github.com/redis/go-redis/v9 v9.5.1 github.com/spf13/cobra v1.8.0 github.com/spf13/viper v1.18.2 github.com/xuri/excelize/v2 v2.8.0 + go.etcd.io/etcd/client/v3 v3.5.13 go.mongodb.org/mongo-driver v1.14.0 + go.uber.org/zap v1.27.0 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df + k8s.io/api v0.31.2 + k8s.io/apimachinery v0.31.2 + k8s.io/client-go v0.31.2 ) require ( @@ -51,23 +56,33 @@ require ( github.com/clbanning/mxj/v2 v2.5.6 // indirect github.com/coreos/go-semver v0.3.0 // indirect github.com/coreos/go-systemd/v22 v22.3.2 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-jose/go-jose/v3 v3.0.3 // indirect + github.com/go-logr/logr v1.4.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/swag v0.22.4 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.18.0 // indirect - github.com/go-zookeeper/zk v1.0.3 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/snappy v0.0.4 // indirect + github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/google/gofuzz v1.2.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect + github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.7 // indirect github.com/klauspost/cpuid/v2 v2.2.6 // indirect @@ -75,11 +90,13 @@ require ( github.com/lestrrat-go/strftime v1.0.6 // indirect github.com/magefile/mage v1.15.0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/richardlehane/mscfb v1.0.4 // indirect github.com/richardlehane/msoleps v1.0.3 // indirect @@ -97,6 +114,7 @@ require ( github.com/twitchtv/twirp v8.1.3+incompatible // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect + github.com/x448/float16 v0.8.4 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect @@ -106,20 +124,28 @@ require ( github.com/yusufpapurcu/wmi v1.2.4 // indirect go.etcd.io/etcd/api/v3 v3.5.13 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.13 // indirect - go.etcd.io/etcd/client/v3 v3.5.13 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.0 // indirect golang.org/x/arch v0.3.0 // indirect - golang.org/x/crypto v0.21.0 // indirect + golang.org/x/crypto v0.24.0 // indirect golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect - golang.org/x/net v0.22.0 // indirect - golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.19.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/net v0.26.0 // indirect + golang.org/x/oauth2 v0.21.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/term v0.21.0 // indirect + golang.org/x/text v0.16.0 // indirect + golang.org/x/time v0.5.0 // indirect google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect + k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index b6f181fe2..a4ec31003 100644 --- a/go.sum +++ b/go.sum @@ -50,6 +50,7 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -60,12 +61,16 @@ github.com/eapache/channels v1.1.0 h1:F1taHcn7/F0i8DYqKXJnyhJcVpp2kgFcNePxXtnyu4 github.com/eapache/channels v1.1.0/go.mod h1:jMm2qB5Ubtg9zLd+inMZd2/NUvXgzmWXsDaLyQIGfH0= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/frostbyte73/core v0.0.10 h1:D4DQXdPb8ICayz0n75rs4UYTXrUSdxzUfeleuNJORsU= github.com/frostbyte73/core v0.0.10/go.mod h1:XsOGqrqe/VEV7+8vJ+3a8qnCIXNbKsoEiu/czs7nrcU= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/gammazero/deque v0.2.1 h1:qSdsbG6pgp6nL7A0+K/B7s12mcCY/5l5SIUpMOl+dC0= @@ -76,10 +81,17 @@ github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= +github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= @@ -88,8 +100,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.18.0 h1:BvolUXjp4zuvkZ5YN5t7ebzbhlUtPsPm2S9NAZ5nl9U= github.com/go-playground/validator/v10 v10.18.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= -github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg= -github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -101,10 +113,16 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= 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/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM= +github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= 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/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -121,6 +139,8 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= @@ -163,6 +183,8 @@ github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg= github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= @@ -178,6 +200,8 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/nats-io/nats.go v1.31.0 h1:/WFBHEc/dOKBF6qf1TZhrdEfTmOZ5JzdJ+Y3m6Y/p7E= github.com/nats-io/nats.go v1.31.0/go.mod h1:di3Bm5MLsoB4Bx61CBTsxuarI36WbhAwOm8QrW39+i8= github.com/nats-io/nkeys v0.4.6 h1:IzVe95ru2CT6ta874rt9saQRkWfe2nFj1NtvYSLqMzY= @@ -185,12 +209,16 @@ github.com/nats-io/nkeys v0.4.6/go.mod h1:4DxZNzenSVd1cYQoAa8948QY3QDjrHfcfVADym github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= +github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= +github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/openimsdk/gomake v0.0.14-alpha.5 h1:VY9c5x515lTfmdhhPjMvR3BBRrRquAUCFsz7t7vbv7Y= github.com/openimsdk/gomake v0.0.14-alpha.5/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI= github.com/openimsdk/protocol v0.0.72 h1:K+vslwaR7lDXyBzb07UuEQITaqsgighz7NyXVIWsu6A= github.com/openimsdk/protocol v0.0.72/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8= -github.com/openimsdk/tools v0.0.50-alpha.20 h1:TUCZOwaea983Qj1MCbiGZUBlwBkTMwTF9SLS0WQcsJs= -github.com/openimsdk/tools v0.0.50-alpha.20/go.mod h1:h1cYmfyaVtgFbKmb1Cfsl8XwUOMTt8ubVUQrdGtsUh4= +github.com/openimsdk/tools v0.0.50-alpha.56 h1:22y0s3IPqgUYrO+r93H8Iq2oW71D5SUe88lkA0asEhU= +github.com/openimsdk/tools v0.0.50-alpha.56/go.mod h1:muCtxguNJv8lFwLei27UASu2Nvg4ERSeN0R4K5tivk0= github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pion/datachannel v1.5.5 h1:10ef4kwdjije+M9d7Xm9im2Y3O6A6ccQb0zcqZcJew8= @@ -247,8 +275,8 @@ github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7 github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg= github.com/richardlehane/msoleps v1.0.3 h1:aznSZzrwYRl3rLKRT3gUk9am7T/mLNSnJINvN0AQoVM= github.com/richardlehane/msoleps v1.0.3/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= @@ -274,8 +302,9 @@ github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMV github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= 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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -299,6 +328,8 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= 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.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= @@ -349,8 +380,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8= @@ -372,16 +403,18 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= -golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -398,8 +431,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -407,6 +440,8 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= +golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -416,8 +451,11 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -426,6 +464,8 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -438,8 +478,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1: google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -448,6 +488,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= @@ -460,4 +502,22 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/gorm v1.25.8 h1:WAGEZ/aEcznN4D03laj8DKnehe1e9gYQAjW8xyPRdeo= gorm.io/gorm v1.25.8/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0= +k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk= +k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw= +k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/client-go v0.31.2 h1:Y2F4dxU5d3AQj+ybwSMqQnpZH9F30//1ObxOKlTI9yc= +k8s.io/client-go v0.31.2/go.mod h1:NPa74jSVR/+eez2dFsEIHNa+3o09vtNaWwWwb1qSxSs= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/internal/api/admin/start.go b/internal/api/admin/start.go index 3aa1e717d..32d2623b9 100644 --- a/internal/api/admin/start.go +++ b/internal/api/admin/start.go @@ -3,6 +3,7 @@ package admin import ( "context" "fmt" + "github.com/gin-gonic/gin" chatmw "github.com/openimsdk/chat/internal/api/mw" "github.com/openimsdk/chat/internal/api/util" @@ -16,6 +17,8 @@ import ( "github.com/openimsdk/tools/utils/datautil" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" + + "github.com/openimsdk/tools/utils/runtimeenv" ) type Config struct { @@ -23,9 +26,13 @@ type Config struct { Discovery config.Discovery Share config.Share + + RuntimeEnv string } func Start(ctx context.Context, index int, config *Config) error { + config.RuntimeEnv = runtimeenv.PrintRuntimeEnvironment() + if len(config.Share.ChatAdmin) == 0 { return errs.New("share chat admin not configured") } @@ -33,16 +40,16 @@ func Start(ctx context.Context, index int, config *Config) error { if err != nil { return err } - client, err := kdisc.NewDiscoveryRegister(&config.Discovery) + client, err := kdisc.NewDiscoveryRegister(&config.Discovery, config.RuntimeEnv) if err != nil { return err } - chatConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Chat, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) + chatConn, err := client.GetConn(ctx, config.Discovery.RpcService.Chat, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) if err != nil { return err } - adminConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Admin, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) + adminConn, err := client.GetConn(ctx, config.Discovery.RpcService.Admin, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) if err != nil { return err } diff --git a/internal/api/chat/start.go b/internal/api/chat/start.go index 81b250cd1..57dc73ce1 100644 --- a/internal/api/chat/start.go +++ b/internal/api/chat/start.go @@ -15,6 +15,7 @@ import ( "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/mw" "github.com/openimsdk/tools/utils/datautil" + "github.com/openimsdk/tools/utils/runtimeenv" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" ) @@ -23,9 +24,13 @@ type Config struct { ApiConfig config.API Discovery config.Discovery Share config.Share + + RuntimeEnv string } func Start(ctx context.Context, index int, config *Config) error { + config.RuntimeEnv = runtimeenv.PrintRuntimeEnvironment() + if len(config.Share.ChatAdmin) == 0 { return errs.New("share chat admin not configured") } @@ -33,16 +38,16 @@ func Start(ctx context.Context, index int, config *Config) error { if err != nil { return err } - client, err := kdisc.NewDiscoveryRegister(&config.Discovery) + client, err := kdisc.NewDiscoveryRegister(&config.Discovery, config.RuntimeEnv) if err != nil { return err } - chatConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Chat, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) + chatConn, err := client.GetConn(ctx, config.Discovery.RpcService.Chat, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) if err != nil { return err } - adminConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Admin, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) + adminConn, err := client.GetConn(ctx, config.Discovery.RpcService.Admin, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) if err != nil { return err } diff --git a/internal/rpc/admin/start.go b/internal/rpc/admin/start.go index d08c31a78..37c6d50b1 100644 --- a/internal/rpc/admin/start.go +++ b/internal/rpc/admin/start.go @@ -21,6 +21,7 @@ import ( "github.com/openimsdk/tools/discovery" "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/mw" + "github.com/openimsdk/tools/utils/runtimeenv" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" ) @@ -31,9 +32,13 @@ type Config struct { MongodbConfig config.Mongo Discovery config.Discovery Share config.Share + + RuntimeEnv string } func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryRegistry, server *grpc.Server) error { + config.RuntimeEnv = runtimeenv.PrintRuntimeEnvironment() + if len(config.Share.ChatAdmin) == 0 { return errs.New("share chat admin not configured") } @@ -55,7 +60,7 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg if err != nil { return err } - conn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Chat, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) + conn, err := client.GetConn(ctx, config.Discovery.RpcService.Chat, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) if err != nil { return err } diff --git a/internal/rpc/chat/start.go b/internal/rpc/chat/start.go index 901b2c5dd..5a867cae4 100644 --- a/internal/rpc/chat/start.go +++ b/internal/rpc/chat/start.go @@ -54,7 +54,7 @@ func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryReg if err != nil { return err } - conn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Admin, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) + conn, err := client.GetConn(ctx, config.Discovery.RpcService.Admin, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) if err != nil { return err } diff --git a/pkg/common/cmd/admin_rpc.go b/pkg/common/cmd/admin_rpc.go index 92a9b3491..3cea0c2f7 100644 --- a/pkg/common/cmd/admin_rpc.go +++ b/pkg/common/cmd/admin_rpc.go @@ -16,6 +16,7 @@ package cmd import ( "context" + "github.com/openimsdk/chat/internal/rpc/admin" "github.com/openimsdk/chat/pkg/common/config" "github.com/openimsdk/chat/pkg/common/startrpc" @@ -54,5 +55,5 @@ func (a *AdminRpcCmd) Exec() error { func (a *AdminRpcCmd) runE() error { return startrpc.Start(a.ctx, &a.adminConfig.Discovery, a.adminConfig.RpcConfig.RPC.ListenIP, a.adminConfig.RpcConfig.RPC.RegisterIP, a.adminConfig.RpcConfig.RPC.Ports, - a.Index(), a.adminConfig.Share.RpcRegisterName.Admin, &a.adminConfig.Share, &a.adminConfig, admin.Start) + a.Index(), a.adminConfig.Discovery.RpcService.Admin, &a.adminConfig.Share, &a.adminConfig, admin.Start) } diff --git a/pkg/common/cmd/chat_rpc.go b/pkg/common/cmd/chat_rpc.go index 92520d928..9bc5e72f6 100644 --- a/pkg/common/cmd/chat_rpc.go +++ b/pkg/common/cmd/chat_rpc.go @@ -16,6 +16,7 @@ package cmd import ( "context" + "github.com/openimsdk/chat/internal/rpc/chat" "github.com/openimsdk/chat/pkg/common/config" "github.com/openimsdk/chat/pkg/common/startrpc" @@ -54,5 +55,5 @@ func (a *ChatRpcCmd) Exec() error { func (a *ChatRpcCmd) runE() error { return startrpc.Start(a.ctx, &a.chatConfig.Discovery, a.chatConfig.RpcConfig.RPC.ListenIP, a.chatConfig.RpcConfig.RPC.RegisterIP, a.chatConfig.RpcConfig.RPC.Ports, - a.Index(), a.chatConfig.Share.RpcRegisterName.Chat, &a.chatConfig.Share, &a.chatConfig, chat.Start) + a.Index(), a.chatConfig.Discovery.RpcService.Chat, &a.chatConfig.Share, &a.chatConfig, chat.Start) } diff --git a/pkg/common/cmd/root.go b/pkg/common/cmd/root.go index 762cbacd8..4cea0a16d 100644 --- a/pkg/common/cmd/root.go +++ b/pkg/common/cmd/root.go @@ -16,13 +16,14 @@ package cmd import ( "fmt" - "path/filepath" "github.com/openimsdk/chat/pkg/common/config" - "github.com/openimsdk/chat/version/version" + "github.com/openimsdk/chat/version" "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/utils/runtimeenv" + "github.com/spf13/cobra" ) @@ -95,18 +96,21 @@ func (r *RootCmd) initializeConfiguration(cmd *cobra.Command, opts *CmdOpts) err if err != nil { return err } + + runtimeEnv := runtimeenv.PrintRuntimeEnvironment() + // Load common configuration file //opts.configMap[ShareFileName] = StructEnvPrefix{EnvPrefix: shareEnvPrefix, ConfigStruct: &r.share} for configFileName, configStruct := range opts.configMap { - err := config.LoadConfig(filepath.Join(configDirectory, configFileName), - ConfigEnvPrefixMap[configFileName], configStruct) + err := config.Load(configDirectory, configFileName, + ConfigEnvPrefixMap[configFileName], runtimeEnv, configStruct) if err != nil { return err } } // Load common log configuration file - return config.LoadConfig(filepath.Join(configDirectory, LogConfigFileName), - ConfigEnvPrefixMap[LogConfigFileName], &r.log) + return config.Load(configDirectory, LogConfigFileName, + ConfigEnvPrefixMap[LogConfigFileName], runtimeEnv, &r.log) } func (r *RootCmd) applyOptions(opts ...func(*CmdOpts)) *CmdOpts { diff --git a/pkg/common/config/config.go b/pkg/common/config/config.go index 2348e9f0e..4acb7ca33 100644 --- a/pkg/common/config/config.go +++ b/pkg/common/config/config.go @@ -15,9 +15,7 @@ var ( ) type Share struct { - Env string `mapstructure:"env"` - RpcRegisterName RpcRegisterName `mapstructure:"rpcRegisterName"` - OpenIM struct { + OpenIM struct { ApiURL string `mapstructure:"apiURL"` Secret string `mapstructure:"secret"` AdminUserID string `mapstructure:"adminUserID"` @@ -26,12 +24,12 @@ type Share struct { ProxyHeader string `mapstructure:"proxyHeader"` } -type RpcRegisterName struct { +type RpcService struct { Chat string `mapstructure:"chat"` Admin string `mapstructure:"admin"` } -func (r *RpcRegisterName) GetServiceNames() []string { +func (r *RpcService) GetServiceNames() []string { return []string{ r.Chat, r.Admin, @@ -51,6 +49,7 @@ type Mongo struct { Database string `mapstructure:"database"` Username string `mapstructure:"username"` Password string `mapstructure:"password"` + AuthSource string `mapstructure:"authSource"` MaxPoolSize int `mapstructure:"maxPoolSize"` MaxRetry int `mapstructure:"maxRetry"` } @@ -62,6 +61,7 @@ func (m *Mongo) Build() *mongoutil.Config { Database: m.Database, Username: m.Username, Password: m.Password, + AuthSource: m.AuthSource, MaxPoolSize: m.MaxPoolSize, MaxRetry: m.MaxRetry, } @@ -88,17 +88,15 @@ func (r *Redis) Build() *redisutil.Config { } } -type ZooKeeper struct { - Schema string `mapstructure:"schema"` - Address []string `mapstructure:"address"` - Username string `mapstructure:"username"` - Password string `mapstructure:"password"` +type Discovery struct { + Enable string `mapstructure:"enable"` + Etcd Etcd `mapstructure:"etcd"` + Kubernetes Kubernetes `mapstructure:"kubernetes"` + RpcService RpcService `mapstructure:"rpcService"` } -type Discovery struct { - Enable string `mapstructure:"enable"` - Etcd Etcd `mapstructure:"etcd"` - ZooKeeper ZooKeeper `mapstructure:"zooKeeper"` +type Kubernetes struct { + Namespace string `mapstructure:"namespace"` } type Etcd struct { diff --git a/pkg/common/config/load.go b/pkg/common/config/load.go index 4101b0b25..9eee55bb6 100644 --- a/pkg/common/config/load.go +++ b/pkg/common/config/load.go @@ -1,13 +1,30 @@ package config import ( + "os" + "path/filepath" + "strings" + "github.com/mitchellh/mapstructure" + "github.com/openimsdk/chat/pkg/common/constant" "github.com/openimsdk/tools/errs" "github.com/spf13/viper" - "strings" ) -func LoadConfig(path string, envPrefix string, config any) error { +func Load(configDirectory string, configFileName string, envPrefix string, runtimeEnv string, config any) error { + if runtimeEnv == constant.KUBERNETES { + mountPath := os.Getenv(constant.MountConfigFilePath) + if mountPath == "" { + return errs.ErrArgs.WrapMsg(constant.MountConfigFilePath + " env is empty") + } + + return loadConfig(filepath.Join(mountPath, configFileName), envPrefix, config) + } + + return loadConfig(filepath.Join(configDirectory, configFileName), envPrefix, config) +} + +func loadConfig(path string, envPrefix string, config any) error { v := viper.New() v.SetConfigFile(path) v.SetEnvPrefix(envPrefix) diff --git a/pkg/common/constant/constant.go b/pkg/common/constant/constant.go index 0c0acec5d..90efe8201 100644 --- a/pkg/common/constant/constant.go +++ b/pkg/common/constant/constant.go @@ -2,6 +2,12 @@ package constant import "github.com/openimsdk/protocol/constant" +const ( + MountConfigFilePath = "CONFIG_PATH" + KUBERNETES = "kubernetes" + ETCD = "etcd" +) + const ( // verificationCode used for. VerificationCodeForRegister = 1 // Register diff --git a/pkg/common/kdisc/discoveryregister.go b/pkg/common/kdisc/discoveryregister.go index 06e2148f1..95d7672b8 100644 --- a/pkg/common/kdisc/discoveryregister.go +++ b/pkg/common/kdisc/discoveryregister.go @@ -15,33 +15,29 @@ package kdisc import ( + "time" + "github.com/openimsdk/chat/pkg/common/config" "github.com/openimsdk/tools/discovery" "github.com/openimsdk/tools/discovery/etcd" - "github.com/openimsdk/tools/discovery/zookeeper" + "github.com/openimsdk/tools/discovery/kubernetes" "github.com/openimsdk/tools/errs" - "time" ) const ( - zookeeperConst = "zookeeper" - kubenetesConst = "k8s" - directConst = "direct" + ETCDCONST = "etcd" + KUBERNETESCONST = "kubernetes" + DIRECTCONST = "direct" ) // NewDiscoveryRegister creates a new service discovery and registry client based on the provided environment type. -func NewDiscoveryRegister(discovery *config.Discovery) (discovery.SvcDiscoveryRegistry, error) { +func NewDiscoveryRegister(discovery *config.Discovery, runtimeEnv string) (discovery.SvcDiscoveryRegistry, error) { + if runtimeEnv == KUBERNETESCONST { + return kubernetes.NewKubernetesConnManager(discovery.Kubernetes.Namespace) + } + switch discovery.Enable { - case "zookeeper": - return zookeeper.NewZkClient( - discovery.ZooKeeper.Address, - discovery.ZooKeeper.Schema, - zookeeper.WithFreq(time.Hour), - zookeeper.WithUserNameAndPassword(discovery.ZooKeeper.Username, discovery.ZooKeeper.Password), - zookeeper.WithRoundRobin(), - zookeeper.WithTimeout(10), - ) - case "etcd": + case ETCDCONST: return etcd.NewSvcDiscoveryRegistry( discovery.Etcd.RootDirectory, discovery.Etcd.Address, diff --git a/pkg/common/kdisc/zookeeper/doc.go b/pkg/common/kdisc/zookeeper/doc.go deleted file mode 100644 index 1c24d77ac..000000000 --- a/pkg/common/kdisc/zookeeper/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright © 2024 OpenIM. 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 zookeeper // import "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/zookeeper" diff --git a/pkg/common/kdisc/zookeeper/zookeeper.go b/pkg/common/kdisc/zookeeper/zookeeper.go deleted file mode 100644 index 1d11414b6..000000000 --- a/pkg/common/kdisc/zookeeper/zookeeper.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright © 2023 OpenIM. 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 zookeeper - -import ( - "os" - "strings" -) - -// getEnv returns the value of an environment variable if it exists, otherwise it returns the fallback value. -func getEnv(key, fallback string) string { - if value, exists := os.LookupEnv(key); exists { - return value - } - return fallback -} - -// getZkAddrFromEnv returns the Zookeeper addresses combined from the ZOOKEEPER_ADDRESS and ZOOKEEPER_PORT environment variables. -// If the environment variables are not set, it returns the fallback value. -func getZkAddrFromEnv(fallback []string) []string { - address, addrExists := os.LookupEnv("ZOOKEEPER_ADDRESS") - port, portExists := os.LookupEnv("ZOOKEEPER_PORT") - - if addrExists && portExists { - addresses := strings.Split(address, ",") - for i, addr := range addresses { - addresses[i] = addr + ":" + port - } - return addresses - } - return fallback -} diff --git a/pkg/common/startrpc/start.go b/pkg/common/startrpc/start.go index ca394c694..d81eb88bb 100644 --- a/pkg/common/startrpc/start.go +++ b/pkg/common/startrpc/start.go @@ -17,9 +17,6 @@ package startrpc import ( "context" "fmt" - "github.com/openimsdk/chat/pkg/common/config" - "github.com/openimsdk/chat/pkg/common/kdisc" - "github.com/openimsdk/tools/utils/datautil" "net" "os" "os/signal" @@ -28,6 +25,11 @@ import ( "syscall" "time" + "github.com/openimsdk/chat/pkg/common/config" + "github.com/openimsdk/chat/pkg/common/kdisc" + "github.com/openimsdk/tools/utils/datautil" + "github.com/openimsdk/tools/utils/runtimeenv" + "github.com/openimsdk/tools/discovery" "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/log" @@ -43,11 +45,13 @@ func Start[T any](ctx context.Context, discovery *config.Discovery, listenIP, registerIP string, rpcPorts []int, index int, rpcRegisterName string, share *config.Share, config T, rpcFn func(ctx context.Context, config T, client discovery.SvcDiscoveryRegistry, server *grpc.Server) error, options ...grpc.ServerOption) error { + runtimeEnv := runtimeenv.PrintRuntimeEnvironment() + rpcPort, err := datautil.GetElemByIndex(rpcPorts, index) if err != nil { return err } - log.CInfo(ctx, "RPC server is initializing", "rpcRegisterName", rpcRegisterName, "rpcPort", rpcPort) + log.CInfo(ctx, "RPC server is initializing", " runtimeEnv ", runtimeEnv, "rpcRegisterName", rpcRegisterName, "rpcPort", rpcPort) rpcTcpAddr := net.JoinHostPort(network.GetListenIP(listenIP), strconv.Itoa(rpcPort)) listener, err := net.Listen( "tcp", @@ -58,7 +62,7 @@ func Start[T any](ctx context.Context, discovery *config.Discovery, listenIP, } defer listener.Close() - client, err := kdisc.NewDiscoveryRegister(discovery) + client, err := kdisc.NewDiscoveryRegister(discovery, runtimeEnv) if err != nil { return err } diff --git a/tools/attribute-to-credential/main.go b/tools/attribute-to-credential/main.go index 315a3c229..d55797948 100644 --- a/tools/attribute-to-credential/main.go +++ b/tools/attribute-to-credential/main.go @@ -4,6 +4,8 @@ import ( "context" "flag" "fmt" + "path/filepath" + "github.com/openimsdk/chat/internal/rpc/chat" "github.com/openimsdk/chat/pkg/common/cmd" "github.com/openimsdk/chat/pkg/common/config" @@ -13,10 +15,10 @@ import ( "github.com/openimsdk/protocol/sdkws" "github.com/openimsdk/tools/db/mongoutil" "github.com/openimsdk/tools/system/program" + "github.com/openimsdk/tools/utils/runtimeenv" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" - "path/filepath" ) const ( @@ -32,7 +34,10 @@ func initConfig(configDir string) (*config.Mongo, error) { var ( mongoConfig = &config.Mongo{} ) - err := config.LoadConfig(filepath.Join(configDir, cmd.MongodbConfigFileName), cmd.ConfigEnvPrefixMap[cmd.MongodbConfigFileName], mongoConfig) + + runtimeEnv := runtimeenv.PrintRuntimeEnvironment() + + err := config.Load(configDir, cmd.MongodbConfigFileName, cmd.ConfigEnvPrefixMap[cmd.MongodbConfigFileName], runtimeEnv, mongoConfig) if err != nil { return nil, err } diff --git a/tools/check-component/main.go b/tools/check-component/main.go index f3f2dd25f..36f488ea3 100644 --- a/tools/check-component/main.go +++ b/tools/check-component/main.go @@ -27,18 +27,14 @@ import ( "github.com/openimsdk/tools/db/mongoutil" "github.com/openimsdk/tools/db/redisutil" "github.com/openimsdk/tools/discovery/etcd" - "github.com/openimsdk/tools/discovery/zookeeper" "github.com/openimsdk/tools/mcontext" "github.com/openimsdk/tools/system/program" "github.com/openimsdk/tools/utils/idutil" + "github.com/openimsdk/tools/utils/runtimeenv" ) const maxRetry = 180 -func CheckZookeeper(ctx context.Context, config *config.ZooKeeper) error { - return zookeeper.Check(ctx, config.Address, config.Schema, zookeeper.WithUserNameAndPassword(config.Username, config.Password)) -} - func CheckEtcd(ctx context.Context, config *config.Etcd) error { return etcd.Check(ctx, config.Address, "/check_chat_component", true, @@ -68,21 +64,24 @@ func initConfig(configDir string) (*config.Mongo, *config.Redis, *config.Discove discoveryConfig = &config.Discovery{} shareConfig = &config.Share{} ) - err := config.LoadConfig(filepath.Join(configDir, cmd.MongodbConfigFileName), cmd.ConfigEnvPrefixMap[cmd.MongodbConfigFileName], mongoConfig) + + runtimeEnv := runtimeenv.PrintRuntimeEnvironment() + + err := config.Load(configDir, cmd.MongodbConfigFileName, cmd.ConfigEnvPrefixMap[cmd.MongodbConfigFileName], runtimeEnv, mongoConfig) if err != nil { return nil, nil, nil, nil, err } - err = config.LoadConfig(filepath.Join(configDir, cmd.RedisConfigFileName), cmd.ConfigEnvPrefixMap[cmd.RedisConfigFileName], redisConfig) + err = config.Load(configDir, cmd.RedisConfigFileName, cmd.ConfigEnvPrefixMap[cmd.RedisConfigFileName], runtimeEnv, redisConfig) if err != nil { return nil, nil, nil, nil, err } - err = config.LoadConfig(filepath.Join(configDir, cmd.DiscoveryConfigFileName), cmd.ConfigEnvPrefixMap[cmd.DiscoveryConfigFileName], discoveryConfig) + err = config.Load(configDir, cmd.DiscoveryConfigFileName, cmd.ConfigEnvPrefixMap[cmd.DiscoveryConfigFileName], runtimeEnv, discoveryConfig) if err != nil { return nil, nil, nil, nil, err } - err = config.LoadConfig(filepath.Join(configDir, cmd.ShareFileName), cmd.ConfigEnvPrefixMap[cmd.ShareFileName], shareConfig) + err = config.Load(configDir, cmd.ShareFileName, cmd.ConfigEnvPrefixMap[cmd.ShareFileName], runtimeEnv, shareConfig) if err != nil { return nil, nil, nil, nil, err } @@ -133,10 +132,6 @@ func performChecks(ctx context.Context, mongoConfig *config.Mongo, redisConfig * checks["Etcd"] = func(ctx context.Context) error { return CheckEtcd(ctx, &discovery.Etcd) } - } else if discovery.Enable == "zookeeper" { - checks["Zookeeper"] = func(ctx context.Context) error { - return CheckZookeeper(ctx, &discovery.ZooKeeper) - } } for i := 0; i < maxRetry; i++ { diff --git a/version/version/version b/version/version similarity index 100% rename from version/version/version rename to version/version diff --git a/version/version/version.go b/version/version.go similarity index 100% rename from version/version/version.go rename to version/version.go From 21c53b2ca284f7fce790733b98e57546cd8f0505 Mon Sep 17 00:00:00 2001 From: Monet Lee Date: Sun, 29 Dec 2024 10:32:14 +0800 Subject: [PATCH 20/36] build: update kubernetes deployment files. (#617) * remove unused contents. * update go version in dockerfile. * build: update kubernetes deployment files. * update go mod. * update deployments docs. * docs: update docs contents. * build: update deployment contents. * docs: update deployment docs. * docs: update deployment docs. * docs: improve docs contents. --- Dockerfile | 4 +- deployments/README.md | 122 ++++++++++++++ deployments/deploy/chat-config.yml | 148 +++++++++++++++++ deployments/deploy/mongo-secret.yml | 8 + .../deploy/openim-admin-api-deployment.yml | 46 ++++++ .../deploy/openim-admin-api-service.yml | 13 ++ .../deploy/openim-admin-rpc-deployment.yml | 46 ++++++ .../deploy/openim-admin-rpc-service.yml | 13 ++ .../deploy/openim-chat-api-deployment.yml | 46 ++++++ .../deploy/openim-chat-api-service.yml | 13 ++ .../deploy/openim-chat-rpc-deployment.yml | 46 ++++++ .../deploy/openim-chat-rpc-service.yml | 13 ++ deployments/deploy/redis-secret.yml | 7 + deployments/helm-charts/.helmignore | 23 --- deployments/helm-charts/Chart.yaml | 38 ----- .../helm-charts/charts/admin-rpc/.helmignore | 23 --- .../helm-charts/charts/admin-rpc/Chart.yaml | 38 ----- .../charts/admin-rpc/templates/NOTES.txt | 22 --- .../charts/admin-rpc/templates/_helpers.tpl | 62 -------- .../admin-rpc/templates/deployment.yaml | 83 ---------- .../charts/admin-rpc/templates/hpa.yaml | 42 ----- .../charts/admin-rpc/templates/ingress.yaml | 75 --------- .../charts/admin-rpc/templates/service.yaml | 29 ---- .../admin-rpc/templates/serviceaccount.yaml | 26 --- .../helm-charts/charts/admin-rpc/values.yaml | 96 ----------- .../helm-charts/charts/chat-api/.helmignore | 23 --- .../helm-charts/charts/chat-api/Chart.yaml | 38 ----- .../charts/chat-api/templates/NOTES.txt | 22 --- .../charts/chat-api/templates/_helpers.tpl | 62 -------- .../charts/chat-api/templates/deployment.yaml | 83 ---------- .../charts/chat-api/templates/hpa.yaml | 42 ----- .../charts/chat-api/templates/ingress.yaml | 75 --------- .../charts/chat-api/templates/service.yaml | 29 ---- .../chat-api/templates/serviceaccount.yaml | 26 --- .../helm-charts/charts/chat-api/values.yaml | 98 ------------ .../helm-charts/charts/chat-rpc/.helmignore | 23 --- .../helm-charts/charts/chat-rpc/Chart.yaml | 38 ----- .../charts/chat-rpc/templates/NOTES.txt | 22 --- .../charts/chat-rpc/templates/_helpers.tpl | 62 -------- .../charts/chat-rpc/templates/deployment.yaml | 83 ---------- .../charts/chat-rpc/templates/hpa.yaml | 42 ----- .../charts/chat-rpc/templates/ingress.yaml | 75 --------- .../charts/chat-rpc/templates/service.yaml | 29 ---- .../chat-rpc/templates/serviceaccount.yaml | 26 --- .../helm-charts/charts/chat-rpc/values.yaml | 96 ----------- deployments/helm-charts/config.yaml | 128 --------------- deployments/helm-charts/templates/NOTES.txt | 22 --- .../helm-charts/templates/_helpers.tpl | 62 -------- deployments/helm-charts/templates/app-cm.yaml | 23 --- .../helm-charts/templates/deployment.yaml | 83 ---------- deployments/helm-charts/templates/hpa.yaml | 42 ----- .../helm-charts/templates/ingress.yaml | 75 --------- .../helm-charts/templates/service.yaml | 29 ---- .../helm-charts/templates/serviceaccount.yaml | 26 --- deployments/helm-charts/values.yaml | 98 ------------ deployments/templates/config.yaml | 150 ------------------ go.mod | 12 +- 57 files changed, 529 insertions(+), 2297 deletions(-) create mode 100644 deployments/README.md create mode 100644 deployments/deploy/chat-config.yml create mode 100644 deployments/deploy/mongo-secret.yml create mode 100644 deployments/deploy/openim-admin-api-deployment.yml create mode 100644 deployments/deploy/openim-admin-api-service.yml create mode 100644 deployments/deploy/openim-admin-rpc-deployment.yml create mode 100644 deployments/deploy/openim-admin-rpc-service.yml create mode 100644 deployments/deploy/openim-chat-api-deployment.yml create mode 100644 deployments/deploy/openim-chat-api-service.yml create mode 100644 deployments/deploy/openim-chat-rpc-deployment.yml create mode 100644 deployments/deploy/openim-chat-rpc-service.yml create mode 100644 deployments/deploy/redis-secret.yml delete mode 100644 deployments/helm-charts/.helmignore delete mode 100644 deployments/helm-charts/Chart.yaml delete mode 100644 deployments/helm-charts/charts/admin-rpc/.helmignore delete mode 100644 deployments/helm-charts/charts/admin-rpc/Chart.yaml delete mode 100644 deployments/helm-charts/charts/admin-rpc/templates/NOTES.txt delete mode 100644 deployments/helm-charts/charts/admin-rpc/templates/_helpers.tpl delete mode 100644 deployments/helm-charts/charts/admin-rpc/templates/deployment.yaml delete mode 100644 deployments/helm-charts/charts/admin-rpc/templates/hpa.yaml delete mode 100644 deployments/helm-charts/charts/admin-rpc/templates/ingress.yaml delete mode 100644 deployments/helm-charts/charts/admin-rpc/templates/service.yaml delete mode 100644 deployments/helm-charts/charts/admin-rpc/templates/serviceaccount.yaml delete mode 100644 deployments/helm-charts/charts/admin-rpc/values.yaml delete mode 100644 deployments/helm-charts/charts/chat-api/.helmignore delete mode 100644 deployments/helm-charts/charts/chat-api/Chart.yaml delete mode 100644 deployments/helm-charts/charts/chat-api/templates/NOTES.txt delete mode 100644 deployments/helm-charts/charts/chat-api/templates/_helpers.tpl delete mode 100644 deployments/helm-charts/charts/chat-api/templates/deployment.yaml delete mode 100644 deployments/helm-charts/charts/chat-api/templates/hpa.yaml delete mode 100644 deployments/helm-charts/charts/chat-api/templates/ingress.yaml delete mode 100644 deployments/helm-charts/charts/chat-api/templates/service.yaml delete mode 100644 deployments/helm-charts/charts/chat-api/templates/serviceaccount.yaml delete mode 100644 deployments/helm-charts/charts/chat-api/values.yaml delete mode 100644 deployments/helm-charts/charts/chat-rpc/.helmignore delete mode 100644 deployments/helm-charts/charts/chat-rpc/Chart.yaml delete mode 100644 deployments/helm-charts/charts/chat-rpc/templates/NOTES.txt delete mode 100644 deployments/helm-charts/charts/chat-rpc/templates/_helpers.tpl delete mode 100644 deployments/helm-charts/charts/chat-rpc/templates/deployment.yaml delete mode 100644 deployments/helm-charts/charts/chat-rpc/templates/hpa.yaml delete mode 100644 deployments/helm-charts/charts/chat-rpc/templates/ingress.yaml delete mode 100644 deployments/helm-charts/charts/chat-rpc/templates/service.yaml delete mode 100644 deployments/helm-charts/charts/chat-rpc/templates/serviceaccount.yaml delete mode 100644 deployments/helm-charts/charts/chat-rpc/values.yaml delete mode 100644 deployments/helm-charts/config.yaml delete mode 100644 deployments/helm-charts/templates/NOTES.txt delete mode 100644 deployments/helm-charts/templates/_helpers.tpl delete mode 100644 deployments/helm-charts/templates/app-cm.yaml delete mode 100644 deployments/helm-charts/templates/deployment.yaml delete mode 100644 deployments/helm-charts/templates/hpa.yaml delete mode 100644 deployments/helm-charts/templates/ingress.yaml delete mode 100644 deployments/helm-charts/templates/service.yaml delete mode 100644 deployments/helm-charts/templates/serviceaccount.yaml delete mode 100644 deployments/helm-charts/values.yaml delete mode 100644 deployments/templates/config.yaml diff --git a/Dockerfile b/Dockerfile index c0076d9cd..8751beace 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Use Go 1.21 Alpine as the base image for building the application -FROM golang:1.21-alpine as builder +FROM golang:1.22-alpine as builder # Define the base directory for the application as an environment variable ENV SERVER_DIR=/openim-chat @@ -22,7 +22,7 @@ RUN go install github.com/magefile/mage@v1.15.0 RUN mage build # Using Alpine Linux with Go environment for the final image -FROM golang:1.21-alpine +FROM golang:1.22-alpine # Install necessary packages, such as bash RUN apk add --no-cache bash diff --git a/deployments/README.md b/deployments/README.md new file mode 100644 index 000000000..09b9e42f1 --- /dev/null +++ b/deployments/README.md @@ -0,0 +1,122 @@ +# OpenIM Chat Deployment + +## Preconditions + +- Ensure deployed OpenIM Server and its dependencies. + - Redis + - MongoDB + - Kafka + - MinIO +- Expose the corresponding Services and ports of OpenIM Server. + +## Deploy OpenIM Chat + +**Chat depends on OpenIM Server, so you need to deploy OpenIM Server first.** + +enter the target directory + +```shell +cd deployments/deploy +``` + +### Modify ConfigMap + +You need to modify the `chat-config.yml` file to match your environment. Focus on the following fields: +**discovery.yml** + +- `kubernetes.namespace`: default is `default`, you can change it to your namespace. + +**mongodb.yml** + +- `address`: set to your already mongodb address or mongo Service name and port in your deployed. +- `database`: set to your mongodb database name.(Need have a created database.) +- `authSource`: et to your mongodb authSource. (authSource is specify the database name associated with the user's credentials, user need create in this database.) + +**redis.yml** + +- `address`: set to your already redis address or redis Service name and port in your deployed. + +**share.yml** + +- `openIM.apiURL`: modify to your already API address or use your `openim-api` service name and port +- `openIM.secret`: same to IM Server `share.secret` value. + +### Set the secret + +A Secret is an object that contains a small amount of sensitive data. Such as password and secret. Secret is similar to ConfigMaps. + +#### Redis: + +Update the `redis-password` value in `redis-secret.yml` to your Redis password encoded in base64. + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: openim-redis-secret +type: Opaque +data: + redis-password: b3BlbklNMTIz # update to your redis password encoded in base64, if need empty, you can set to "" +``` + +#### Mongo: + +Update the `mongo_openim_username`, `mongo_openim_password` value in `mongo-secret.yml` to your Mongo username and password encoded in base64. + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: openim-mongo-secret +type: Opaque +data: + mongo_openim_username: b3BlbklN # update to your mongo username encoded in base64, if need empty, you can set to "" (this user credentials need in authSource database) + mongo_openim_password: b3BlbklNMTIz # update to your mongo password encoded in base64, if need empty, you can set to "" +``` + +### Apply the secret. + +```shell +kubectl apply -f redis-secret.yml -f mongo-secret.yml +``` + +### Apply Config and Services + +deploy the config and services + +```shell +kubectl apply -f chat-config.yml -f openim-admin-api-service.yml -f openim-chat-api-service.yml -f openim-admin-rpc-service.yml -f openim-chat-rpc-service.yml +``` + +### Start Chat Deployments + +```shell +kubectl apply -f openim-chat-api-deployment.yml -f openim-admin-api-deployment.yml -f openim-chat-rpc-deployment.yml -f openim-admin-rpc-deployment.yml +``` + +## Verify + +After the deployment is complete, you can verify the deployment status. + +```shell +# Check the status of all pods +kubectl get pods + +# Check the status of services +kubectl get svc + +# Check the status of deployments +kubectl get deployments + +# View all resources +kubectl get all + +``` + +## clean all + +`kubectl delete -f ./` + +## Notes: + +- If you use a specific namespace for your deployment, be sure to append the -n flag to your kubectl commands. diff --git a/deployments/deploy/chat-config.yml b/deployments/deploy/chat-config.yml new file mode 100644 index 000000000..330d69122 --- /dev/null +++ b/deployments/deploy/chat-config.yml @@ -0,0 +1,148 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: openim-chat-config +data: + discovery.yml: | + enable: kubernetes + kubernetes: + namespace: default + etcd: + rootDirectory: openim + address: [ localhost:12379 ] + username: '' + password: '' + + rpcService: + chat: chat-rpc-service + admin: admin-rpc-service + + log.yml: | + # Log storage path, default is acceptable, change to a full path if modification is needed + # storageLocation: ../../../../logs/ + storageLocation: ./logs/ + # Log rotation period (in hours), default is acceptable + rotationTime: 24 + # Number of log files to retain, default is acceptable + remainRotationCount: 2 + # Log level settings: 3 for production environment; 6 for more verbose logging in debugging environments + remainLogLevel: 6 + # Whether to output to standard output, default is acceptable + isStdout: true + # Whether to log in JSON format, default is acceptable + isJson: false + # output simplify log when KeyAndValues's value len is bigger than 50 in rpc method log + isSimplify: true + + mongodb.yml: | + # URI for database connection, leave empty if using address and credential settings directly + uri: '' + # List of MongoDB server addresses + address: [ mongo-service:37017 ] + # Name of the database + database: openim_v3 + # Username for database authentication + username: openIM + # Password for database authentication + password: # openIM123 + # Authentication source for database authentication, if use root user, set it to admin + authSource: openim_v3 + # Maximum number of connections in the connection pool + maxPoolSize: 100 + # Maximum number of retry attempts for a failed database connection + maxRetry: 10 + + redis.yml: | + # List of Redis server addresses + address: [ redis-service:16379 ] + # Username for Redis authentication (leave blank if not used) + username: '' + # Password for Redis authentication + password: # openIM123 + # Enable or disable pipeline processing + enablePipeline: false + # Enable or disable cluster mode + clusterMode: false + # Database index to be used + db: 0 + # Maximum number of retry attempts for a failed connection + maxRetry: 10 + + share.yml: | + openIM: + # OpenIM API address + apiURL: http://openim-api-service:10002 + # OpenIM secret key, must be consistent with OpenIM + secret: openIM123 + # OpenIM administrator userID, must be consistent with OpenIM + adminUserID: imAdmin + + chatAdmin: + # Default username and password for the admin + - "chatAdmin" + + chat-api-admin.yml: | + api: + # Listening IP; 0.0.0.0 means both internal and external IPs are listened to, default is recommended + listenIP: 0.0.0.0 + # Listening ports; if multiple are configured, multiple instances will be launched + ports: [ 10009 ] + + chat-rpc-admin.yml: | + rpc: + # The IP address where this RPC service registers itself; if left blank, it defaults to the internal network IP + registerIP: '' + # IP address that the RPC service listens on; setting to 0.0.0.0 listens on both internal and external IPs. If left blank, it automatically uses the internal network IP + listenIP: 0.0.0.0 + # List of ports that the RPC service listens on; configuring multiple ports will launch multiple instances. + ports: [ 30200 ] + + tokenPolicy: + expire: 90 + + secret: chat123 + chat-api-chat.yml: | + api: + # Listening IP; 0.0.0.0 means both internal and external IPs are listened to, default is recommended + listenIP: 0.0.0.0 + # Listening ports; if multiple are configured, multiple instances will be launched + ports: [ 10008 ] + + chat-rpc-chat.yml: | + rpc: + # The IP address where this RPC service registers itself; if left blank, it defaults to the internal network IP + registerIP: '' + # IP address that the RPC service listens on; setting to 0.0.0.0 listens on both internal and external IPs. If left blank, it automatically uses the internal network IP + listenIP: 0.0.0.0 + # List of ports that the RPC service listens on; configuring multiple ports will launch multiple instances. + ports: [ 30300 ] + + verifyCode: + validTime: 300 + validCount: 5 + uintTime: 86400 + maxCount: 10 + superCode: "666666" + len: 6 + phone: + use: "" + ali: + endpoint: "" + accessKeyId: "" + accessKeySecret: "" + signName: "" + verificationCodeTemplateCode: "" + mail: + enable: false + title: "" + senderMail: "" + senderAuthorizationCode: "" + smtpAddr: "" + smtpPort: + + liveKit: + url: "ws://127.0.0.1:7880" # LIVEKIT_URL, LiveKit server address and port + key: "APIGPW3gnFTzqHH" + secret: "23ztfSqsfQ8hKkHzHTl3Z4bvaxro0snjk5jwbp5p6Q3" + + allowRegister: true diff --git a/deployments/deploy/mongo-secret.yml b/deployments/deploy/mongo-secret.yml new file mode 100644 index 000000000..c3c10af24 --- /dev/null +++ b/deployments/deploy/mongo-secret.yml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: openim-mongo-secret +type: Opaque +data: + mongo_openim_username: b3BlbklN # base64 for "openIM", this user credentials need in authSource database. + mongo_openim_password: b3BlbklNMTIz # base64 for "openIM123" diff --git a/deployments/deploy/openim-admin-api-deployment.yml b/deployments/deploy/openim-admin-api-deployment.yml new file mode 100644 index 000000000..8f7baddfc --- /dev/null +++ b/deployments/deploy/openim-admin-api-deployment.yml @@ -0,0 +1,46 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: admin-api-server +spec: + replicas: 1 + selector: + matchLabels: + app: admin-api-server + template: + metadata: + labels: + app: admin-api-server + spec: + containers: + - name: openim-admin-api-container + image: openim/openim-admin-api:v3.8.3 + env: + - name: CONFIG_PATH + value: "/config" + - name: CHATENV_REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: redis-secret + key: redis-password + - name: IMENV_MONGODB_USERNAME + valueFrom: + secretKeyRef: + name: openim-mongo-secret + key: mongo_openim_username + - name: CHATENV_MONGODB_PASSWORD + valueFrom: + secretKeyRef: + name: mongo-secret + key: mongo_openim_password + + volumeMounts: + - name: openim-chat-config + mountPath: "/config" + readOnly: true + ports: + - containerPort: 10009 + volumes: + - name: openim-chat-config + configMap: + name: openim-chat-config diff --git a/deployments/deploy/openim-admin-api-service.yml b/deployments/deploy/openim-admin-api-service.yml new file mode 100644 index 000000000..dcb723b14 --- /dev/null +++ b/deployments/deploy/openim-admin-api-service.yml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: admin-api-service +spec: + selector: + app: admin-api-server + ports: + - name: http-10009 + protocol: TCP + port: 10009 + targetPort: 10009 + type: NodePort diff --git a/deployments/deploy/openim-admin-rpc-deployment.yml b/deployments/deploy/openim-admin-rpc-deployment.yml new file mode 100644 index 000000000..3c7a30e57 --- /dev/null +++ b/deployments/deploy/openim-admin-rpc-deployment.yml @@ -0,0 +1,46 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: admin-rpc-server +spec: + replicas: 1 + selector: + matchLabels: + app: admin-rpc-server + template: + metadata: + labels: + app: admin-rpc-server + spec: + containers: + - name: openim-admin-rpc-container + image: openim/openim-admin-rpc:v3.8.3 + env: + - name: CONFIG_PATH + value: "/config" + - name: CHATENV_REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: redis-secret + key: redis-password + - name: IMENV_MONGODB_USERNAME + valueFrom: + secretKeyRef: + name: openim-mongo-secret + key: mongo_openim_username + - name: CHATENV_MONGODB_PASSWORD + valueFrom: + secretKeyRef: + name: mongo-secret + key: mongo_openim_password + + volumeMounts: + - name: openim-chat-config + mountPath: "/config" + readOnly: true + ports: + - containerPort: 30200 + volumes: + - name: openim-chat-config + configMap: + name: openim-chat-config diff --git a/deployments/deploy/openim-admin-rpc-service.yml b/deployments/deploy/openim-admin-rpc-service.yml new file mode 100644 index 000000000..100e43103 --- /dev/null +++ b/deployments/deploy/openim-admin-rpc-service.yml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: admin-rpc-service +spec: + selector: + app: admin-rpc-server + ports: + - name: rpc-30200 + protocol: TCP + port: 30200 + targetPort: 30200 + type: ClusterIP diff --git a/deployments/deploy/openim-chat-api-deployment.yml b/deployments/deploy/openim-chat-api-deployment.yml new file mode 100644 index 000000000..8465d862a --- /dev/null +++ b/deployments/deploy/openim-chat-api-deployment.yml @@ -0,0 +1,46 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: chat-api-server +spec: + replicas: 1 + selector: + matchLabels: + app: chat-api-server + template: + metadata: + labels: + app: chat-api-server + spec: + containers: + - name: openim-chat-api-container + image: openim/openim-chat-api:v3.8.3 + env: + - name: CONFIG_PATH + value: "/config" + - name: CHATENV_REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: redis-secret + key: redis-password + - name: IMENV_MONGODB_USERNAME + valueFrom: + secretKeyRef: + name: openim-mongo-secret + key: mongo_openim_username + - name: CHATENV_MONGODB_PASSWORD + valueFrom: + secretKeyRef: + name: mongo-secret + key: mongo_openim_password + + volumeMounts: + - name: openim-chat-config + mountPath: "/config" + readOnly: true + ports: + - containerPort: 10008 + volumes: + - name: openim-chat-config + configMap: + name: openim-chat-config diff --git a/deployments/deploy/openim-chat-api-service.yml b/deployments/deploy/openim-chat-api-service.yml new file mode 100644 index 000000000..43a777e31 --- /dev/null +++ b/deployments/deploy/openim-chat-api-service.yml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: chat-api-service +spec: + selector: + app: chat-api-server + ports: + - name: http-10008 + protocol: TCP + port: 10008 + targetPort: 10008 + type: NodePort diff --git a/deployments/deploy/openim-chat-rpc-deployment.yml b/deployments/deploy/openim-chat-rpc-deployment.yml new file mode 100644 index 000000000..81ea3d67e --- /dev/null +++ b/deployments/deploy/openim-chat-rpc-deployment.yml @@ -0,0 +1,46 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: chat-rpc-server +spec: + replicas: 1 + selector: + matchLabels: + app: chat-rpc-server + template: + metadata: + labels: + app: chat-rpc-server + spec: + containers: + - name: openim-chat-rpc-container + image: openim/openim-chat-rpc:v3.8.3 + env: + - name: CONFIG_PATH + value: "/config" + - name: CHATENV_REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: redis-secret + key: redis-password + - name: IMENV_MONGODB_USERNAME + valueFrom: + secretKeyRef: + name: openim-mongo-secret + key: mongo_openim_username + - name: CHATENV_MONGODB_PASSWORD + valueFrom: + secretKeyRef: + name: mongo-secret + key: mongo_openim_password + + volumeMounts: + - name: openim-chat-config + mountPath: "/config" + readOnly: true + ports: + - containerPort: 30300 + volumes: + - name: openim-chat-config + configMap: + name: openim-chat-config diff --git a/deployments/deploy/openim-chat-rpc-service.yml b/deployments/deploy/openim-chat-rpc-service.yml new file mode 100644 index 000000000..e245e45f1 --- /dev/null +++ b/deployments/deploy/openim-chat-rpc-service.yml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: chat-rpc-service +spec: + selector: + app: chat-rpc-server + ports: + - name: rpc-30300 + protocol: TCP + port: 30300 + targetPort: 30300 + type: ClusterIP diff --git a/deployments/deploy/redis-secret.yml b/deployments/deploy/redis-secret.yml new file mode 100644 index 000000000..463ec9545 --- /dev/null +++ b/deployments/deploy/redis-secret.yml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Secret +metadata: + name: openim-redis-secret +type: Opaque +data: + redis-password: b3BlbklNMTIz # "openIM123" in base64 diff --git a/deployments/helm-charts/.helmignore b/deployments/helm-charts/.helmignore deleted file mode 100644 index 0e8a0eb36..000000000 --- a/deployments/helm-charts/.helmignore +++ /dev/null @@ -1,23 +0,0 @@ -# Patterns to ignore when building packages. -# This supports shell glob matching, relative path matching, and -# negation (prefixed with !). Only one pattern per line. -.DS_Store -# Common VCS dirs -.git/ -.gitignore -.bzr/ -.bzrignore -.hg/ -.hgignore -.svn/ -# Common backup files -*.swp -*.bak -*.tmp -*.orig -*~ -# Various IDEs -.project -.idea/ -*.tmproj -.vscode/ diff --git a/deployments/helm-charts/Chart.yaml b/deployments/helm-charts/Chart.yaml deleted file mode 100644 index b96fa7961..000000000 --- a/deployments/helm-charts/Chart.yaml +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -apiVersion: v2 -name: admin-api -description: A Helm chart for Kubernetes - -# A chart can be either an 'application' or a 'library' chart. -# -# Application charts are a collection of templates that can be packaged into versioned archives -# to be deployed. -# -# Library charts provide useful utilities or functions for the chart developer. They're included as -# a dependency of application charts to inject those utilities and functions into the rendering -# pipeline. Library charts do not define any templates and therefore cannot be deployed. -type: application - -# This is the chart version. This version number should be incremented each time you make changes -# to the chart and its templates, including the app version. -# Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.0 - -# This is the version number of the application being deployed. This version number should be -# incremented each time you make changes to the application. Versions are not expected to -# follow Semantic Versioning. They should reflect the version the application is using. -# It is recommended to use it with quotes. -appVersion: "1.16.0" diff --git a/deployments/helm-charts/charts/admin-rpc/.helmignore b/deployments/helm-charts/charts/admin-rpc/.helmignore deleted file mode 100644 index 0e8a0eb36..000000000 --- a/deployments/helm-charts/charts/admin-rpc/.helmignore +++ /dev/null @@ -1,23 +0,0 @@ -# Patterns to ignore when building packages. -# This supports shell glob matching, relative path matching, and -# negation (prefixed with !). Only one pattern per line. -.DS_Store -# Common VCS dirs -.git/ -.gitignore -.bzr/ -.bzrignore -.hg/ -.hgignore -.svn/ -# Common backup files -*.swp -*.bak -*.tmp -*.orig -*~ -# Various IDEs -.project -.idea/ -*.tmproj -.vscode/ diff --git a/deployments/helm-charts/charts/admin-rpc/Chart.yaml b/deployments/helm-charts/charts/admin-rpc/Chart.yaml deleted file mode 100644 index 7b1761050..000000000 --- a/deployments/helm-charts/charts/admin-rpc/Chart.yaml +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -apiVersion: v2 -name: admin-rpc -description: A Helm chart for Kubernetes - -# A chart can be either an 'application' or a 'library' chart. -# -# Application charts are a collection of templates that can be packaged into versioned archives -# to be deployed. -# -# Library charts provide useful utilities or functions for the chart developer. They're included as -# a dependency of application charts to inject those utilities and functions into the rendering -# pipeline. Library charts do not define any templates and therefore cannot be deployed. -type: application - -# This is the chart version. This version number should be incremented each time you make changes -# to the chart and its templates, including the app version. -# Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.0 - -# This is the version number of the application being deployed. This version number should be -# incremented each time you make changes to the application. Versions are not expected to -# follow Semantic Versioning. They should reflect the version the application is using. -# It is recommended to use it with quotes. -appVersion: "1.16.0" diff --git a/deployments/helm-charts/charts/admin-rpc/templates/NOTES.txt b/deployments/helm-charts/charts/admin-rpc/templates/NOTES.txt deleted file mode 100644 index cb5db3d55..000000000 --- a/deployments/helm-charts/charts/admin-rpc/templates/NOTES.txt +++ /dev/null @@ -1,22 +0,0 @@ -1. Get the application URL by running these commands: -{{- if .Values.ingress.enabled }} -{{- range $host := .Values.ingress.hosts }} - {{- range .paths }} - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} - {{- end }} -{{- end }} -{{- else if contains "NodePort" .Values.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "admin-rpc.fullname" . }}) - export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") - echo http://$NODE_IP:$NODE_PORT -{{- else if contains "LoadBalancer" .Values.service.type }} - NOTE: It may take a few minutes for the LoadBalancer IP to be available. - You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "admin-rpc.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "admin-rpc.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:{{ .Values.service.port }} -{{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "admin-rpc.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") - export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") - echo "Visit http://127.0.0.1:8080 to use your application" - kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT -{{- end }} diff --git a/deployments/helm-charts/charts/admin-rpc/templates/_helpers.tpl b/deployments/helm-charts/charts/admin-rpc/templates/_helpers.tpl deleted file mode 100644 index b6da95769..000000000 --- a/deployments/helm-charts/charts/admin-rpc/templates/_helpers.tpl +++ /dev/null @@ -1,62 +0,0 @@ -{{/* -Expand the name of the chart. -*/}} -{{- define "admin-rpc.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "admin-rpc.fullname" -}} -{{- if .Values.fullnameOverride }} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- $name := default .Chart.Name .Values.nameOverride }} -{{- if contains $name .Release.Name }} -{{- .Release.Name | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} -{{- end }} -{{- end }} -{{- end }} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "admin-rpc.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Common labels -*/}} -{{- define "admin-rpc.labels" -}} -helm.sh/chart: {{ include "admin-rpc.chart" . }} -{{ include "admin-rpc.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Selector labels -*/}} -{{- define "admin-rpc.selectorLabels" -}} -app.kubernetes.io/name: {{ include "admin-rpc.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} - -{{/* -Create the name of the service account to use -*/}} -{{- define "admin-rpc.serviceAccountName" -}} -{{- if .Values.serviceAccount.create }} -{{- default (include "admin-rpc.fullname" .) .Values.serviceAccount.name }} -{{- else }} -{{- default "default" .Values.serviceAccount.name }} -{{- end }} -{{- end }} diff --git a/deployments/helm-charts/charts/admin-rpc/templates/deployment.yaml b/deployments/helm-charts/charts/admin-rpc/templates/deployment.yaml deleted file mode 100644 index 5fb1e3834..000000000 --- a/deployments/helm-charts/charts/admin-rpc/templates/deployment.yaml +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "admin-rpc.fullname" . }} - labels: - {{- include "admin-rpc.labels" . | nindent 4 }} -spec: - {{- if not .Values.autoscaling.enabled }} - replicas: {{ .Values.replicaCount }} - {{- end }} - selector: - matchLabels: - {{- include "admin-rpc.selectorLabels" . | nindent 6 }} - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "admin-rpc.selectorLabels" . | nindent 8 }} - spec: - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - serviceAccountName: {{ include "admin-rpc.serviceAccountName" . }} - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - containers: - - name: {{ .Chart.Name }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - ports: - - name: http - containerPort: 80 - protocol: TCP - #livenessProbe: - # httpGet: - # path: / - # port: http - #readinessProbe: - # httpGet: - # path: / - # port: http - resources: - {{- toYaml .Values.resources | nindent 12 }} - volumeMounts: - - mountPath: /app/config/config.yaml - name: config - subPath: config.yaml - volumes: - - name: config - configMap: - name: imchat-cm - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} diff --git a/deployments/helm-charts/charts/admin-rpc/templates/hpa.yaml b/deployments/helm-charts/charts/admin-rpc/templates/hpa.yaml deleted file mode 100644 index 27755e494..000000000 --- a/deployments/helm-charts/charts/admin-rpc/templates/hpa.yaml +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -{{- if .Values.autoscaling.enabled }} -apiVersion: autoscaling/v2beta1 -kind: HorizontalPodAutoscaler -metadata: - name: {{ include "admin-rpc.fullname" . }} - labels: - {{- include "admin-rpc.labels" . | nindent 4 }} -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: {{ include "admin-rpc.fullname" . }} - minReplicas: {{ .Values.autoscaling.minReplicas }} - maxReplicas: {{ .Values.autoscaling.maxReplicas }} - metrics: - {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} - - type: Resource - resource: - name: cpu - targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} - {{- end }} - {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} - - type: Resource - resource: - name: memory - targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} - {{- end }} -{{- end }} diff --git a/deployments/helm-charts/charts/admin-rpc/templates/ingress.yaml b/deployments/helm-charts/charts/admin-rpc/templates/ingress.yaml deleted file mode 100644 index 3d9466030..000000000 --- a/deployments/helm-charts/charts/admin-rpc/templates/ingress.yaml +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -{{- if .Values.ingress.enabled -}} -{{- $fullName := include "admin-rpc.fullname" . -}} -{{- $svcPort := .Values.service.port -}} -{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} - {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} - {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} - {{- end }} -{{- end }} -{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} -apiVersion: networking.k8s.io/v1 -{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} -apiVersion: networking.k8s.io/v1beta1 -{{- else -}} -apiVersion: extensions/v1beta1 -{{- end }} -kind: Ingress -metadata: - name: {{ $fullName }} - labels: - {{- include "admin-rpc.labels" . | nindent 4 }} - {{- with .Values.ingress.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -spec: - {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} - ingressClassName: {{ .Values.ingress.className }} - {{- end }} - {{- if .Values.ingress.tls }} - tls: - {{- range .Values.ingress.tls }} - - hosts: - {{- range .hosts }} - - {{ . | quote }} - {{- end }} - secretName: {{ .secretName }} - {{- end }} - {{- end }} - rules: - {{- range .Values.ingress.hosts }} - - host: {{ .host | quote }} - http: - paths: - {{- range .paths }} - - path: {{ .path }} - {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} - pathType: {{ .pathType }} - {{- end }} - backend: - {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} - service: - name: {{ $fullName }} - port: - number: {{ $svcPort }} - {{- else }} - serviceName: {{ $fullName }} - servicePort: {{ $svcPort }} - {{- end }} - {{- end }} - {{- end }} -{{- end }} diff --git a/deployments/helm-charts/charts/admin-rpc/templates/service.yaml b/deployments/helm-charts/charts/admin-rpc/templates/service.yaml deleted file mode 100644 index a5b0dca54..000000000 --- a/deployments/helm-charts/charts/admin-rpc/templates/service.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -apiVersion: v1 -kind: Service -metadata: - name: {{ include "admin-rpc.fullname" . }} - labels: - {{- include "admin-rpc.labels" . | nindent 4 }} -spec: - type: {{ .Values.service.type }} - ports: - - port: {{ .Values.service.port }} - targetPort: http - protocol: TCP - name: http - selector: - {{- include "admin-rpc.selectorLabels" . | nindent 4 }} diff --git a/deployments/helm-charts/charts/admin-rpc/templates/serviceaccount.yaml b/deployments/helm-charts/charts/admin-rpc/templates/serviceaccount.yaml deleted file mode 100644 index 417951552..000000000 --- a/deployments/helm-charts/charts/admin-rpc/templates/serviceaccount.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -{{- if .Values.serviceAccount.create -}} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "admin-rpc.serviceAccountName" . }} - labels: - {{- include "admin-rpc.labels" . | nindent 4 }} - {{- with .Values.serviceAccount.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -{{- end }} diff --git a/deployments/helm-charts/charts/admin-rpc/values.yaml b/deployments/helm-charts/charts/admin-rpc/values.yaml deleted file mode 100644 index ee7225e6b..000000000 --- a/deployments/helm-charts/charts/admin-rpc/values.yaml +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -# Default values for admin-rpc. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - -replicaCount: 1 - -image: - repository: nginx - pullPolicy: IfNotPresent - # Overrides the image tag whose default is the chart appVersion. - tag: "" - -imagePullSecrets: [] -nameOverride: "" -fullnameOverride: "" - -serviceAccount: - # Specifies whether a service account should be created - create: false - # Annotations to add to the service account - annotations: {} - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template - name: "" - -podAnnotations: {} - -podSecurityContext: {} - # fsGroup: 2000 - -securityContext: {} - # capabilities: - # drop: - # - ALL - # readOnlyRootFilesystem: true - # runAsNonRoot: true - # runAsUser: 1000 - -service: - type: ClusterIP - port: 80 - -ingress: - enabled: false - className: "" - annotations: {} - # kubernetes.io/ingress.class: nginx - # kubernetes.io/tls-acme: "true" - hosts: - - host: chart-example.local - paths: - - path: / - pathType: ImplementationSpecific - tls: [] - # - secretName: chart-example-tls - # hosts: - # - chart-example.local - -resources: {} - # We usually recommend not to specify default resources and to leave this as a conscious - # choice for the user. This also increases chances charts run on environments with little - # resources, such as Minikube. If you do want to specify resources, uncomment the following - # lines, adjust them as necessary, and remove the curly braces after 'resources:'. - # limits: - # cpu: 100m - # memory: 128Mi - # requests: - # cpu: 100m - # memory: 128Mi - -autoscaling: - enabled: false - minReplicas: 1 - maxReplicas: 100 - targetCPUUtilizationPercentage: 80 - # targetMemoryUtilizationPercentage: 80 - -nodeSelector: {} - -tolerations: [] - -affinity: {} diff --git a/deployments/helm-charts/charts/chat-api/.helmignore b/deployments/helm-charts/charts/chat-api/.helmignore deleted file mode 100644 index 0e8a0eb36..000000000 --- a/deployments/helm-charts/charts/chat-api/.helmignore +++ /dev/null @@ -1,23 +0,0 @@ -# Patterns to ignore when building packages. -# This supports shell glob matching, relative path matching, and -# negation (prefixed with !). Only one pattern per line. -.DS_Store -# Common VCS dirs -.git/ -.gitignore -.bzr/ -.bzrignore -.hg/ -.hgignore -.svn/ -# Common backup files -*.swp -*.bak -*.tmp -*.orig -*~ -# Various IDEs -.project -.idea/ -*.tmproj -.vscode/ diff --git a/deployments/helm-charts/charts/chat-api/Chart.yaml b/deployments/helm-charts/charts/chat-api/Chart.yaml deleted file mode 100644 index a82e9e115..000000000 --- a/deployments/helm-charts/charts/chat-api/Chart.yaml +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -apiVersion: v2 -name: chat-api -description: A Helm chart for Kubernetes - -# A chart can be either an 'application' or a 'library' chart. -# -# Application charts are a collection of templates that can be packaged into versioned archives -# to be deployed. -# -# Library charts provide useful utilities or functions for the chart developer. They're included as -# a dependency of application charts to inject those utilities and functions into the rendering -# pipeline. Library charts do not define any templates and therefore cannot be deployed. -type: application - -# This is the chart version. This version number should be incremented each time you make changes -# to the chart and its templates, including the app version. -# Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.0 - -# This is the version number of the application being deployed. This version number should be -# incremented each time you make changes to the application. Versions are not expected to -# follow Semantic Versioning. They should reflect the version the application is using. -# It is recommended to use it with quotes. -appVersion: "1.16.0" diff --git a/deployments/helm-charts/charts/chat-api/templates/NOTES.txt b/deployments/helm-charts/charts/chat-api/templates/NOTES.txt deleted file mode 100644 index 012270869..000000000 --- a/deployments/helm-charts/charts/chat-api/templates/NOTES.txt +++ /dev/null @@ -1,22 +0,0 @@ -1. Get the application URL by running these commands: -{{- if .Values.ingress.enabled }} -{{- range $host := .Values.ingress.hosts }} - {{- range .paths }} - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} - {{- end }} -{{- end }} -{{- else if contains "NodePort" .Values.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "chat-api.fullname" . }}) - export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") - echo http://$NODE_IP:$NODE_PORT -{{- else if contains "LoadBalancer" .Values.service.type }} - NOTE: It may take a few minutes for the LoadBalancer IP to be available. - You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "chat-api.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "chat-api.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:{{ .Values.service.port }} -{{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "chat-api.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") - export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") - echo "Visit http://127.0.0.1:8080 to use your application" - kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT -{{- end }} diff --git a/deployments/helm-charts/charts/chat-api/templates/_helpers.tpl b/deployments/helm-charts/charts/chat-api/templates/_helpers.tpl deleted file mode 100644 index a7a4c2c28..000000000 --- a/deployments/helm-charts/charts/chat-api/templates/_helpers.tpl +++ /dev/null @@ -1,62 +0,0 @@ -{{/* -Expand the name of the chart. -*/}} -{{- define "chat-api.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "chat-api.fullname" -}} -{{- if .Values.fullnameOverride }} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- $name := default .Chart.Name .Values.nameOverride }} -{{- if contains $name .Release.Name }} -{{- .Release.Name | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} -{{- end }} -{{- end }} -{{- end }} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "chat-api.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Common labels -*/}} -{{- define "chat-api.labels" -}} -helm.sh/chart: {{ include "chat-api.chart" . }} -{{ include "chat-api.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Selector labels -*/}} -{{- define "chat-api.selectorLabels" -}} -app.kubernetes.io/name: {{ include "chat-api.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} - -{{/* -Create the name of the service account to use -*/}} -{{- define "chat-api.serviceAccountName" -}} -{{- if .Values.serviceAccount.create }} -{{- default (include "chat-api.fullname" .) .Values.serviceAccount.name }} -{{- else }} -{{- default "default" .Values.serviceAccount.name }} -{{- end }} -{{- end }} diff --git a/deployments/helm-charts/charts/chat-api/templates/deployment.yaml b/deployments/helm-charts/charts/chat-api/templates/deployment.yaml deleted file mode 100644 index d29efdf1d..000000000 --- a/deployments/helm-charts/charts/chat-api/templates/deployment.yaml +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "chat-api.fullname" . }} - labels: - {{- include "chat-api.labels" . | nindent 4 }} -spec: - {{- if not .Values.autoscaling.enabled }} - replicas: {{ .Values.replicaCount }} - {{- end }} - selector: - matchLabels: - {{- include "chat-api.selectorLabels" . | nindent 6 }} - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "chat-api.selectorLabels" . | nindent 8 }} - spec: - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - serviceAccountName: {{ include "chat-api.serviceAccountName" . }} - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - containers: - - name: {{ .Chart.Name }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - ports: - - name: http - containerPort: 80 - protocol: TCP - #livenessProbe: - # httpGet: - # path: / - # port: http - #readinessProbe: - # httpGet: - # path: / - # port: http - resources: - {{- toYaml .Values.resources | nindent 12 }} - volumeMounts: - - mountPath: /app/config/config.yaml - name: config - subPath: config.yaml - volumes: - - name: config - configMap: - name: imchat-cm - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} diff --git a/deployments/helm-charts/charts/chat-api/templates/hpa.yaml b/deployments/helm-charts/charts/chat-api/templates/hpa.yaml deleted file mode 100644 index f6d63e828..000000000 --- a/deployments/helm-charts/charts/chat-api/templates/hpa.yaml +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -{{- if .Values.autoscaling.enabled }} -apiVersion: autoscaling/v2beta1 -kind: HorizontalPodAutoscaler -metadata: - name: {{ include "chat-api.fullname" . }} - labels: - {{- include "chat-api.labels" . | nindent 4 }} -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: {{ include "chat-api.fullname" . }} - minReplicas: {{ .Values.autoscaling.minReplicas }} - maxReplicas: {{ .Values.autoscaling.maxReplicas }} - metrics: - {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} - - type: Resource - resource: - name: cpu - targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} - {{- end }} - {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} - - type: Resource - resource: - name: memory - targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} - {{- end }} -{{- end }} diff --git a/deployments/helm-charts/charts/chat-api/templates/ingress.yaml b/deployments/helm-charts/charts/chat-api/templates/ingress.yaml deleted file mode 100644 index 43ecdb75a..000000000 --- a/deployments/helm-charts/charts/chat-api/templates/ingress.yaml +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -{{- if .Values.ingress.enabled -}} -{{- $fullName := include "chat-api.fullname" . -}} -{{- $svcPort := .Values.service.port -}} -{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} - {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} - {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} - {{- end }} -{{- end }} -{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} -apiVersion: networking.k8s.io/v1 -{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} -apiVersion: networking.k8s.io/v1beta1 -{{- else -}} -apiVersion: extensions/v1beta1 -{{- end }} -kind: Ingress -metadata: - name: {{ $fullName }} - labels: - {{- include "chat-api.labels" . | nindent 4 }} - {{- with .Values.ingress.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -spec: - {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} - ingressClassName: {{ .Values.ingress.className }} - {{- end }} - {{- if .Values.ingress.tls }} - tls: - {{- range .Values.ingress.tls }} - - hosts: - {{- range .hosts }} - - {{ . | quote }} - {{- end }} - secretName: {{ .secretName }} - {{- end }} - {{- end }} - rules: - {{- range .Values.ingress.hosts }} - - host: {{ .host | quote }} - http: - paths: - {{- range .paths }} - - path: {{ .path }} - {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} - pathType: {{ .pathType }} - {{- end }} - backend: - {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} - service: - name: {{ $fullName }} - port: - number: {{ $svcPort }} - {{- else }} - serviceName: {{ $fullName }} - servicePort: {{ $svcPort }} - {{- end }} - {{- end }} - {{- end }} -{{- end }} diff --git a/deployments/helm-charts/charts/chat-api/templates/service.yaml b/deployments/helm-charts/charts/chat-api/templates/service.yaml deleted file mode 100644 index ec844e288..000000000 --- a/deployments/helm-charts/charts/chat-api/templates/service.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -apiVersion: v1 -kind: Service -metadata: - name: {{ include "chat-api.fullname" . }} - labels: - {{- include "chat-api.labels" . | nindent 4 }} -spec: - type: {{ .Values.service.type }} - ports: - - port: {{ .Values.service.port }} - targetPort: http - protocol: TCP - name: http - selector: - {{- include "chat-api.selectorLabels" . | nindent 4 }} diff --git a/deployments/helm-charts/charts/chat-api/templates/serviceaccount.yaml b/deployments/helm-charts/charts/chat-api/templates/serviceaccount.yaml deleted file mode 100644 index 52f3aabda..000000000 --- a/deployments/helm-charts/charts/chat-api/templates/serviceaccount.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -{{- if .Values.serviceAccount.create -}} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "chat-api.serviceAccountName" . }} - labels: - {{- include "chat-api.labels" . | nindent 4 }} - {{- with .Values.serviceAccount.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -{{- end }} diff --git a/deployments/helm-charts/charts/chat-api/values.yaml b/deployments/helm-charts/charts/chat-api/values.yaml deleted file mode 100644 index 4aa411610..000000000 --- a/deployments/helm-charts/charts/chat-api/values.yaml +++ /dev/null @@ -1,98 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -# Default values for chat-api. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - -replicaCount: 1 - -image: - repository: nginx - pullPolicy: IfNotPresent - # Overrides the image tag whose default is the chart appVersion. - tag: "" - -imagePullSecrets: [] -nameOverride: "" -fullnameOverride: "" - -serviceAccount: - # Specifies whether a service account should be created - create: false - # Annotations to add to the service account - annotations: {} - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template - name: "" - -podAnnotations: {} - -podSecurityContext: {} - # fsGroup: 2000 - -securityContext: {} - # capabilities: - # drop: - # - ALL - # readOnlyRootFilesystem: true - # runAsNonRoot: true - # runAsUser: 1000 - -service: - type: ClusterIP - port: 80 - -ingress: - enabled: true - className: "nginx" - annotations: - # kubernetes.io/ingress.class: nginx - # kubernetes.io/tls-acme: "true" - nginx.ingress.kubernetes.io/use-regex: "true" - nginx.ingress.kubernetes.io/rewrite-target: /$2 - hosts: - - host: openim1.nsddd.top - paths: - - path: /chat(/|$)(.*) - pathType: ImplementationSpecific - tls: [] - # - secretName: chart-example-tls - # hosts: - # - chart-example.local - -resources: {} - # We usually recommend not to specify default resources and to leave this as a conscious - # choice for the user. This also increases chances charts run on environments with little - # resources, such as Minikube. If you do want to specify resources, uncomment the following - # lines, adjust them as necessary, and remove the curly braces after 'resources:'. - # limits: - # cpu: 100m - # memory: 128Mi - # requests: - # cpu: 100m - # memory: 128Mi - -autoscaling: - enabled: false - minReplicas: 1 - maxReplicas: 100 - targetCPUUtilizationPercentage: 80 - # targetMemoryUtilizationPercentage: 80 - -nodeSelector: {} - -tolerations: [] - -affinity: {} diff --git a/deployments/helm-charts/charts/chat-rpc/.helmignore b/deployments/helm-charts/charts/chat-rpc/.helmignore deleted file mode 100644 index 0e8a0eb36..000000000 --- a/deployments/helm-charts/charts/chat-rpc/.helmignore +++ /dev/null @@ -1,23 +0,0 @@ -# Patterns to ignore when building packages. -# This supports shell glob matching, relative path matching, and -# negation (prefixed with !). Only one pattern per line. -.DS_Store -# Common VCS dirs -.git/ -.gitignore -.bzr/ -.bzrignore -.hg/ -.hgignore -.svn/ -# Common backup files -*.swp -*.bak -*.tmp -*.orig -*~ -# Various IDEs -.project -.idea/ -*.tmproj -.vscode/ diff --git a/deployments/helm-charts/charts/chat-rpc/Chart.yaml b/deployments/helm-charts/charts/chat-rpc/Chart.yaml deleted file mode 100644 index a3ffcbbd0..000000000 --- a/deployments/helm-charts/charts/chat-rpc/Chart.yaml +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -apiVersion: v2 -name: chat-rpc -description: A Helm chart for Kubernetes - -# A chart can be either an 'application' or a 'library' chart. -# -# Application charts are a collection of templates that can be packaged into versioned archives -# to be deployed. -# -# Library charts provide useful utilities or functions for the chart developer. They're included as -# a dependency of application charts to inject those utilities and functions into the rendering -# pipeline. Library charts do not define any templates and therefore cannot be deployed. -type: application - -# This is the chart version. This version number should be incremented each time you make changes -# to the chart and its templates, including the app version. -# Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.0 - -# This is the version number of the application being deployed. This version number should be -# incremented each time you make changes to the application. Versions are not expected to -# follow Semantic Versioning. They should reflect the version the application is using. -# It is recommended to use it with quotes. -appVersion: "1.16.0" diff --git a/deployments/helm-charts/charts/chat-rpc/templates/NOTES.txt b/deployments/helm-charts/charts/chat-rpc/templates/NOTES.txt deleted file mode 100644 index 2f1beaee5..000000000 --- a/deployments/helm-charts/charts/chat-rpc/templates/NOTES.txt +++ /dev/null @@ -1,22 +0,0 @@ -1. Get the application URL by running these commands: -{{- if .Values.ingress.enabled }} -{{- range $host := .Values.ingress.hosts }} - {{- range .paths }} - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} - {{- end }} -{{- end }} -{{- else if contains "NodePort" .Values.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "chat-rpc.fullname" . }}) - export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") - echo http://$NODE_IP:$NODE_PORT -{{- else if contains "LoadBalancer" .Values.service.type }} - NOTE: It may take a few minutes for the LoadBalancer IP to be available. - You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "chat-rpc.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "chat-rpc.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:{{ .Values.service.port }} -{{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "chat-rpc.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") - export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") - echo "Visit http://127.0.0.1:8080 to use your application" - kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT -{{- end }} diff --git a/deployments/helm-charts/charts/chat-rpc/templates/_helpers.tpl b/deployments/helm-charts/charts/chat-rpc/templates/_helpers.tpl deleted file mode 100644 index 9edc1981c..000000000 --- a/deployments/helm-charts/charts/chat-rpc/templates/_helpers.tpl +++ /dev/null @@ -1,62 +0,0 @@ -{{/* -Expand the name of the chart. -*/}} -{{- define "chat-rpc.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "chat-rpc.fullname" -}} -{{- if .Values.fullnameOverride }} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- $name := default .Chart.Name .Values.nameOverride }} -{{- if contains $name .Release.Name }} -{{- .Release.Name | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} -{{- end }} -{{- end }} -{{- end }} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "chat-rpc.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Common labels -*/}} -{{- define "chat-rpc.labels" -}} -helm.sh/chart: {{ include "chat-rpc.chart" . }} -{{ include "chat-rpc.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Selector labels -*/}} -{{- define "chat-rpc.selectorLabels" -}} -app.kubernetes.io/name: {{ include "chat-rpc.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} - -{{/* -Create the name of the service account to use -*/}} -{{- define "chat-rpc.serviceAccountName" -}} -{{- if .Values.serviceAccount.create }} -{{- default (include "chat-rpc.fullname" .) .Values.serviceAccount.name }} -{{- else }} -{{- default "default" .Values.serviceAccount.name }} -{{- end }} -{{- end }} diff --git a/deployments/helm-charts/charts/chat-rpc/templates/deployment.yaml b/deployments/helm-charts/charts/chat-rpc/templates/deployment.yaml deleted file mode 100644 index da9df7e1f..000000000 --- a/deployments/helm-charts/charts/chat-rpc/templates/deployment.yaml +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "chat-rpc.fullname" . }} - labels: - {{- include "chat-rpc.labels" . | nindent 4 }} -spec: - {{- if not .Values.autoscaling.enabled }} - replicas: {{ .Values.replicaCount }} - {{- end }} - selector: - matchLabels: - {{- include "chat-rpc.selectorLabels" . | nindent 6 }} - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "chat-rpc.selectorLabels" . | nindent 8 }} - spec: - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - serviceAccountName: {{ include "chat-rpc.serviceAccountName" . }} - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - containers: - - name: {{ .Chart.Name }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - ports: - - name: http - containerPort: 80 - protocol: TCP - #livenessProbe: - # httpGet: - # path: / - # port: http - #readinessProbe: - # httpGet: - # path: / - # port: http - resources: - {{- toYaml .Values.resources | nindent 12 }} - volumeMounts: - - mountPath: /app/config/config.yaml - name: config - subPath: config.yaml - volumes: - - name: config - configMap: - name: imchat-cm - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} diff --git a/deployments/helm-charts/charts/chat-rpc/templates/hpa.yaml b/deployments/helm-charts/charts/chat-rpc/templates/hpa.yaml deleted file mode 100644 index f54187544..000000000 --- a/deployments/helm-charts/charts/chat-rpc/templates/hpa.yaml +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -{{- if .Values.autoscaling.enabled }} -apiVersion: autoscaling/v2beta1 -kind: HorizontalPodAutoscaler -metadata: - name: {{ include "chat-rpc.fullname" . }} - labels: - {{- include "chat-rpc.labels" . | nindent 4 }} -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: {{ include "chat-rpc.fullname" . }} - minReplicas: {{ .Values.autoscaling.minReplicas }} - maxReplicas: {{ .Values.autoscaling.maxReplicas }} - metrics: - {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} - - type: Resource - resource: - name: cpu - targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} - {{- end }} - {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} - - type: Resource - resource: - name: memory - targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} - {{- end }} -{{- end }} diff --git a/deployments/helm-charts/charts/chat-rpc/templates/ingress.yaml b/deployments/helm-charts/charts/chat-rpc/templates/ingress.yaml deleted file mode 100644 index 1b292c080..000000000 --- a/deployments/helm-charts/charts/chat-rpc/templates/ingress.yaml +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -{{- if .Values.ingress.enabled -}} -{{- $fullName := include "chat-rpc.fullname" . -}} -{{- $svcPort := .Values.service.port -}} -{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} - {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} - {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} - {{- end }} -{{- end }} -{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} -apiVersion: networking.k8s.io/v1 -{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} -apiVersion: networking.k8s.io/v1beta1 -{{- else -}} -apiVersion: extensions/v1beta1 -{{- end }} -kind: Ingress -metadata: - name: {{ $fullName }} - labels: - {{- include "chat-rpc.labels" . | nindent 4 }} - {{- with .Values.ingress.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -spec: - {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} - ingressClassName: {{ .Values.ingress.className }} - {{- end }} - {{- if .Values.ingress.tls }} - tls: - {{- range .Values.ingress.tls }} - - hosts: - {{- range .hosts }} - - {{ . | quote }} - {{- end }} - secretName: {{ .secretName }} - {{- end }} - {{- end }} - rules: - {{- range .Values.ingress.hosts }} - - host: {{ .host | quote }} - http: - paths: - {{- range .paths }} - - path: {{ .path }} - {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} - pathType: {{ .pathType }} - {{- end }} - backend: - {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} - service: - name: {{ $fullName }} - port: - number: {{ $svcPort }} - {{- else }} - serviceName: {{ $fullName }} - servicePort: {{ $svcPort }} - {{- end }} - {{- end }} - {{- end }} -{{- end }} diff --git a/deployments/helm-charts/charts/chat-rpc/templates/service.yaml b/deployments/helm-charts/charts/chat-rpc/templates/service.yaml deleted file mode 100644 index a24600366..000000000 --- a/deployments/helm-charts/charts/chat-rpc/templates/service.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -apiVersion: v1 -kind: Service -metadata: - name: {{ include "chat-rpc.fullname" . }} - labels: - {{- include "chat-rpc.labels" . | nindent 4 }} -spec: - type: {{ .Values.service.type }} - ports: - - port: {{ .Values.service.port }} - targetPort: http - protocol: TCP - name: http - selector: - {{- include "chat-rpc.selectorLabels" . | nindent 4 }} diff --git a/deployments/helm-charts/charts/chat-rpc/templates/serviceaccount.yaml b/deployments/helm-charts/charts/chat-rpc/templates/serviceaccount.yaml deleted file mode 100644 index 8705421da..000000000 --- a/deployments/helm-charts/charts/chat-rpc/templates/serviceaccount.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -{{- if .Values.serviceAccount.create -}} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "chat-rpc.serviceAccountName" . }} - labels: - {{- include "chat-rpc.labels" . | nindent 4 }} - {{- with .Values.serviceAccount.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -{{- end }} diff --git a/deployments/helm-charts/charts/chat-rpc/values.yaml b/deployments/helm-charts/charts/chat-rpc/values.yaml deleted file mode 100644 index 719f8553a..000000000 --- a/deployments/helm-charts/charts/chat-rpc/values.yaml +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -# Default values for chat-rpc. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - -replicaCount: 1 - -image: - repository: nginx - pullPolicy: IfNotPresent - # Overrides the image tag whose default is the chart appVersion. - tag: "" - -imagePullSecrets: [] -nameOverride: "" -fullnameOverride: "" - -serviceAccount: - # Specifies whether a service account should be created - create: false - # Annotations to add to the service account - annotations: {} - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template - name: "" - -podAnnotations: {} - -podSecurityContext: {} - # fsGroup: 2000 - -securityContext: {} - # capabilities: - # drop: - # - ALL - # readOnlyRootFilesystem: true - # runAsNonRoot: true - # runAsUser: 1000 - -service: - type: ClusterIP - port: 80 - -ingress: - enabled: false - className: "" - annotations: {} - # kubernetes.io/ingress.class: nginx - # kubernetes.io/tls-acme: "true" - hosts: - - host: chart-example.local - paths: - - path: / - pathType: ImplementationSpecific - tls: [] - # - secretName: chart-example-tls - # hosts: - # - chart-example.local - -resources: {} - # We usually recommend not to specify default resources and to leave this as a conscious - # choice for the user. This also increases chances charts run on environments with little - # resources, such as Minikube. If you do want to specify resources, uncomment the following - # lines, adjust them as necessary, and remove the curly braces after 'resources:'. - # limits: - # cpu: 100m - # memory: 128Mi - # requests: - # cpu: 100m - # memory: 128Mi - -autoscaling: - enabled: false - minReplicas: 1 - maxReplicas: 100 - targetCPUUtilizationPercentage: 80 - # targetMemoryUtilizationPercentage: 80 - -nodeSelector: {} - -tolerations: [] - -affinity: {} diff --git a/deployments/helm-charts/config.yaml b/deployments/helm-charts/config.yaml deleted file mode 100644 index 6be98c93f..000000000 --- a/deployments/helm-charts/config.yaml +++ /dev/null @@ -1,128 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -image: - repository: registry.cn-shenzhen.aliyuncs.com/huanglin_hub/admin-api - pullPolicy: Always - tag: "dev" -admin-rpc: - image: - repository: registry.cn-shenzhen.aliyuncs.com/huanglin_hub/admin-rpc - pullPolicy: Always - tag: "dev" -chat-api: - image: - repository: registry.cn-shenzhen.aliyuncs.com/huanglin_hub/chat-api - pullPolicy: Always - tag: "dev" -chat-rpc: - image: - repository: registry.cn-shenzhen.aliyuncs.com/huanglin_hub/chat-rpc - pullPolicy: Always - tag: "dev" - -config: - envs: - discovery: k8s - zookeeper: - schema: openim - zkAddr: - - 127.0.0.1:12181 - username: "" - password: "" - - chatApi: - openImChatApiPort: [ 80 ] - listenIP: - - adminApi: - openImAdminApiPort: [ 80 ] - listenIP: - - rpc: - registerIP: - listenIP: - - rpcPort: - openImAdminPort: [ 80 ] - openImChatPort: [ 80 ] - rpcRegisterName: - openImAdminName: openimchat-admin-rpc:80 - openImChatName: openimchat-chat-rpc:80 - - - mysql: - address: [ im-mysql:3306 ] - username: root - password: openIM123 - #database: openIM_v2 - maxOpenConn: 1000 - maxIdleConn: 100 - maxLifeTime: 60 - logLevel: 4 - slowThreshold: 500 - database: openim_enterprise - - - log: - storageLocation: ../_output/logs/ - rotationTime: 24 - remainRotationCount: 2 - remainLogLevel: 6 - isStdout: true - isJson: false - withStack: false - - secret: openIM123 - chatSecret: openIM123 - - tokenPolicy: - expire: 86400 - - verifyCode: - validTime: 300 - validCount: 5 - uintTime: 86400 - maxCount: 10 - superCode: "666666" - len: 6 - use: "" - ali: - endpoint: "dysmsapi.aliyuncs.com" - accessKeyId: "" - accessKeySecret: "" - signName: "" - verificationCodeTemplateCode: "" - - - #proxyHeader: "X-Forwarded-For" - - adminList: - - adminID: admin1 - nickname: chat1 - imAdmin: openIM123456 - - adminID: admin2 - nickname: chat2 - imAdmin: openIM654321 - - adminID: admin3 - nickname: chat3 - imAdmin: openIMAdmin - - - openIMUrl: "http://openimserver-openim-api" - - redis: - address: [ im-redis-master:6379 ] - username: '' - password: openIM123 diff --git a/deployments/helm-charts/templates/NOTES.txt b/deployments/helm-charts/templates/NOTES.txt deleted file mode 100644 index 9cbe57754..000000000 --- a/deployments/helm-charts/templates/NOTES.txt +++ /dev/null @@ -1,22 +0,0 @@ -1. Get the application URL by running these commands: -{{- if .Values.ingress.enabled }} -{{- range $host := .Values.ingress.hosts }} - {{- range .paths }} - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} - {{- end }} -{{- end }} -{{- else if contains "NodePort" .Values.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "admin-api.fullname" . }}) - export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") - echo http://$NODE_IP:$NODE_PORT -{{- else if contains "LoadBalancer" .Values.service.type }} - NOTE: It may take a few minutes for the LoadBalancer IP to be available. - You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "admin-api.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "admin-api.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:{{ .Values.service.port }} -{{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "admin-api.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") - export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") - echo "Visit http://127.0.0.1:8080 to use your application" - kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT -{{- end }} diff --git a/deployments/helm-charts/templates/_helpers.tpl b/deployments/helm-charts/templates/_helpers.tpl deleted file mode 100644 index 10ad4b5e4..000000000 --- a/deployments/helm-charts/templates/_helpers.tpl +++ /dev/null @@ -1,62 +0,0 @@ -{{/* -Expand the name of the chart. -*/}} -{{- define "admin-api.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "admin-api.fullname" -}} -{{- if .Values.fullnameOverride }} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- $name := default .Chart.Name .Values.nameOverride }} -{{- if contains $name .Release.Name }} -{{- .Release.Name | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} -{{- end }} -{{- end }} -{{- end }} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "admin-api.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Common labels -*/}} -{{- define "admin-api.labels" -}} -helm.sh/chart: {{ include "admin-api.chart" . }} -{{ include "admin-api.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Selector labels -*/}} -{{- define "admin-api.selectorLabels" -}} -app.kubernetes.io/name: {{ include "admin-api.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} - -{{/* -Create the name of the service account to use -*/}} -{{- define "admin-api.serviceAccountName" -}} -{{- if .Values.serviceAccount.create }} -{{- default (include "admin-api.fullname" .) .Values.serviceAccount.name }} -{{- else }} -{{- default "default" .Values.serviceAccount.name }} -{{- end }} -{{- end }} diff --git a/deployments/helm-charts/templates/app-cm.yaml b/deployments/helm-charts/templates/app-cm.yaml deleted file mode 100644 index e01c895a6..000000000 --- a/deployments/helm-charts/templates/app-cm.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -apiVersion: v1 -kind: ConfigMap -metadata: - name: imchat-cm -data: - config.yaml: |+ - {{- with .Values.config }} - {{- toYaml . | nindent 4 }} - {{- end }} diff --git a/deployments/helm-charts/templates/deployment.yaml b/deployments/helm-charts/templates/deployment.yaml deleted file mode 100644 index a8cd54f32..000000000 --- a/deployments/helm-charts/templates/deployment.yaml +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "admin-api.fullname" . }} - labels: - {{- include "admin-api.labels" . | nindent 4 }} -spec: - {{- if not .Values.autoscaling.enabled }} - replicas: {{ .Values.replicaCount }} - {{- end }} - selector: - matchLabels: - {{- include "admin-api.selectorLabels" . | nindent 6 }} - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "admin-api.selectorLabels" . | nindent 8 }} - spec: - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - serviceAccountName: {{ include "admin-api.serviceAccountName" . }} - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - containers: - - name: {{ .Chart.Name }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - ports: - - name: http - containerPort: 80 - protocol: TCP - #livenessProbe: - # httpGet: - # path: / - # port: http - #readinessProbe: - # httpGet: - # path: / - # port: http - resources: - {{- toYaml .Values.resources | nindent 12 }} - volumeMounts: - - mountPath: /app/config/config.yaml - name: config - subPath: config.yaml - volumes: - - name: config - configMap: - name: imchat-cm - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} diff --git a/deployments/helm-charts/templates/hpa.yaml b/deployments/helm-charts/templates/hpa.yaml deleted file mode 100644 index 3ffac34d9..000000000 --- a/deployments/helm-charts/templates/hpa.yaml +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -{{- if .Values.autoscaling.enabled }} -apiVersion: autoscaling/v2beta1 -kind: HorizontalPodAutoscaler -metadata: - name: {{ include "admin-api.fullname" . }} - labels: - {{- include "admin-api.labels" . | nindent 4 }} -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: {{ include "admin-api.fullname" . }} - minReplicas: {{ .Values.autoscaling.minReplicas }} - maxReplicas: {{ .Values.autoscaling.maxReplicas }} - metrics: - {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} - - type: Resource - resource: - name: cpu - targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} - {{- end }} - {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} - - type: Resource - resource: - name: memory - targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} - {{- end }} -{{- end }} diff --git a/deployments/helm-charts/templates/ingress.yaml b/deployments/helm-charts/templates/ingress.yaml deleted file mode 100644 index 2580e9cd2..000000000 --- a/deployments/helm-charts/templates/ingress.yaml +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -{{- if .Values.ingress.enabled -}} -{{- $fullName := include "admin-api.fullname" . -}} -{{- $svcPort := .Values.service.port -}} -{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} - {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} - {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} - {{- end }} -{{- end }} -{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} -apiVersion: networking.k8s.io/v1 -{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} -apiVersion: networking.k8s.io/v1beta1 -{{- else -}} -apiVersion: extensions/v1beta1 -{{- end }} -kind: Ingress -metadata: - name: {{ $fullName }} - labels: - {{- include "admin-api.labels" . | nindent 4 }} - {{- with .Values.ingress.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -spec: - {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} - ingressClassName: {{ .Values.ingress.className }} - {{- end }} - {{- if .Values.ingress.tls }} - tls: - {{- range .Values.ingress.tls }} - - hosts: - {{- range .hosts }} - - {{ . | quote }} - {{- end }} - secretName: {{ .secretName }} - {{- end }} - {{- end }} - rules: - {{- range .Values.ingress.hosts }} - - host: {{ .host | quote }} - http: - paths: - {{- range .paths }} - - path: {{ .path }} - {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} - pathType: {{ .pathType }} - {{- end }} - backend: - {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} - service: - name: {{ $fullName }} - port: - number: {{ $svcPort }} - {{- else }} - serviceName: {{ $fullName }} - servicePort: {{ $svcPort }} - {{- end }} - {{- end }} - {{- end }} -{{- end }} diff --git a/deployments/helm-charts/templates/service.yaml b/deployments/helm-charts/templates/service.yaml deleted file mode 100644 index e5d385f7f..000000000 --- a/deployments/helm-charts/templates/service.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -apiVersion: v1 -kind: Service -metadata: - name: {{ include "admin-api.fullname" . }} - labels: - {{- include "admin-api.labels" . | nindent 4 }} -spec: - type: {{ .Values.service.type }} - ports: - - port: {{ .Values.service.port }} - targetPort: http - protocol: TCP - name: http - selector: - {{- include "admin-api.selectorLabels" . | nindent 4 }} diff --git a/deployments/helm-charts/templates/serviceaccount.yaml b/deployments/helm-charts/templates/serviceaccount.yaml deleted file mode 100644 index c0c056579..000000000 --- a/deployments/helm-charts/templates/serviceaccount.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -{{- if .Values.serviceAccount.create -}} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "admin-api.serviceAccountName" . }} - labels: - {{- include "admin-api.labels" . | nindent 4 }} - {{- with .Values.serviceAccount.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -{{- end }} diff --git a/deployments/helm-charts/values.yaml b/deployments/helm-charts/values.yaml deleted file mode 100644 index 2664d3d87..000000000 --- a/deployments/helm-charts/values.yaml +++ /dev/null @@ -1,98 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -# Default values for admin-api. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - -replicaCount: 1 - -image: - repository: nginx - pullPolicy: IfNotPresent - # Overrides the image tag whose default is the chart appVersion. - tag: "" - -imagePullSecrets: [] -nameOverride: "" -fullnameOverride: "" - -serviceAccount: - # Specifies whether a service account should be created - create: false - # Annotations to add to the service account - annotations: {} - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template - name: "" - -podAnnotations: {} - -podSecurityContext: {} - # fsGroup: 2000 - -securityContext: {} - # capabilities: - # drop: - # - ALL - # readOnlyRootFilesystem: true - # runAsNonRoot: true - # runAsUser: 1000 - -service: - type: ClusterIP - port: 80 - -ingress: - enabled: true - className: "nginx" - annotations: - # kubernetes.io/ingress.class: nginx - # kubernetes.io/tls-acme: "true" - nginx.ingress.kubernetes.io/use-regex: "true" - nginx.ingress.kubernetes.io/rewrite-target: /$2 - hosts: - - host: openim1.nsddd.top - paths: - - path: /complete_admin(/|$)(.*) - pathType: ImplementationSpecific - tls: [] - # - secretName: chart-example-tls - # hosts: - # - chart-example.local - -resources: {} - # We usually recommend not to specify default resources and to leave this as a conscious - # choice for the user. This also increases chances charts run on environments with little - # resources, such as Minikube. If you do want to specify resources, uncomment the following - # lines, adjust them as necessary, and remove the curly braces after 'resources:'. - # limits: - # cpu: 100m - # memory: 128Mi - # requests: - # cpu: 100m - # memory: 128Mi - -autoscaling: - enabled: false - minReplicas: 1 - maxReplicas: 100 - targetCPUUtilizationPercentage: 80 - # targetMemoryUtilizationPercentage: 80 - -nodeSelector: {} - -tolerations: [] - -affinity: {} diff --git a/deployments/templates/config.yaml b/deployments/templates/config.yaml deleted file mode 100644 index 60cb5f0fb..000000000 --- a/deployments/templates/config.yaml +++ /dev/null @@ -1,150 +0,0 @@ -# Copyright © 2023 OpenIM open source community. 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. - -# OpenIM Server should be started before this configuration is applied -envs: - discovery: "zookeeper" # ENVS_DISCOVERY, e.g., zookeeper, etcd... - -# Zookeeper configuration - used for service discovery and coordination -zookeeper: - schema: openim # ZOOKEEPER_SCHEMA, the schema to use in Zookeeper - zkAddr: - - 172.28.0.1:12181 # ZOOKEEPER_ADDRESS and ZOOKEEPER_PORT, Zookeeper address and port - username: "" # ZOOKEEPER_USERNAME, Username for Zookeeper authentication - password: "" # ZOOKEEPER_PASSWORD, Password for Zookeeper authentication - -# Configuration for the chat API service -chatApi: - openImChatApiPort: [ 10008 ] # Port for OpenIM Chat API - listenIP: # CHAT_API_LISTEN_IP, IP address to listen on for Chat API - -# Configuration for the admin API service -adminApi: - openImAdminApiPort: [ 10009 ] # Port for OpenIM Admin API - listenIP: # ADMIN_API_LISTEN_IP, IP address to listen on for Admin API - -# RPC configuration for service communication -rpc: - registerIP: # RPC_REGISTER_IP, IP address to register with Zookeeper for RPC - listenIP: # RPC_LISTEN_IP, IP address to listen on for RPC (default 0.0.0.0) - -# Ports for RPC services -rpcPort: - openImAdminPort: [ 30200 ] # Port for OpenIM Admin RPC service - openImChatPort: [ 30300 ] # Port for OpenIM Chat RPC service - -# Names for RPC services registration -rpcRegisterName: - openImAdminName: admin # Name for OpenIM Admin RPC service - openImChatName: chat # Name for OpenIM Chat RPC service - -# Log configuration - defines how logging is handled -log: - storageLocation: ../_output/logs/ # LOG_STORAGE_LOCATION, Directory for storing logs - rotationTime: 24 # Log rotation time in hours - remainRotationCount: 2 # Number of log files to retain - remainLogLevel: 6 # Log level (6 = all levels) - isStdout: false # Whether to output logs to stdout - isJson: false # Whether to output logs in JSON format - withStack: false # Whether to include stack trace in logs - -# Secret key for secure communication -secret: openIM123 # SECRET, Secret key for encryption and secure communication - -# Token policy configuration -tokenPolicy: - expire: 86400 # TOKEN_EXPIRE, Token expiration time in seconds - -# Verification code settings -verifyCode: - validTime: 300 # Verification code valid time in seconds - validCount: 5 # Number of times a verification code is valid - uintTime: 86400 # Time unit for verification code - maxCount: 10 # Maximum number of verification codes in a time unit - superCode: "666666" # Super verification code (used only when `use` is empty) - len: 6 # Length of the verification code - use: "" # Service used for verification code (e.g., "ali") - # Aliyun SMS service configuration - ali: - endpoint: "dysmsapi.aliyuncs.com" - accessKeyId: "" - accessKeySecret: "" - signName: "" - verificationCodeTemplateCode: "" - # Email service configuration - mail: - title: "" - senderMail: "" # Email address of the sender - senderAuthorizationCode: "" # Authorization code for the sender's email - smtpAddr: "smtp.qq.com" # SMTP server address - smtpPort: 465 # SMTP server port for email sending - -# Proxy header configuration for IP extraction -# proxyHeader: "X-Forwarded-For" # PROXY_HEADER, Header used for extracting the client IP address - -# List of admin users -# Attention! This configure is discarded. If you have used him before, configure your own -adminList: - - adminID: - nickname: - imAdmin: - - adminID: - nickname: - imAdmin: - - adminID: - nickname: - imAdmin: - -# chatAdmin, use for send notification -chatAdmin: - - adminID: chatAdmin - nickname: chatAdmin - imAdmin: imAdmin - -# URL for OpenIM server -openIMUrl: "http://172.28.0.1:10002" # OPENIM_SERVER_ADDRESS:API_OPENIM_PORT, URL of the OpenIM server - -# Redis configuration - used for caching and session management -redis: - address: [ 172.28.0.1:16379 ] # REDIS_ADDRESS and REDIS_PORT, Redis server address and port - username: # REDIS_USERNAME, Username for Redis authentication - password: openIM123 # REDIS_PASSWORD, Password for Redis - -# LiveKit configuration - used for video and audio rtc -liveKit: - liveKitUrl: "ws://172.28.0.1:7880" # LIVEKIT_URL, LiveKit server address and port - key: "APIDXJxJeCL8haY" # LIVEKIT_API_KEY - secret: "ak1qulJ3nfXeflQHWBdmQDc4js4ueMc5OnxoORVJC2xA" # LIVEKIT_API_SECRET - -# MongoDB configuration - -# If uri is not empty, it will be used directly for the MongoDB connection. -# This is a complete MongoDB URI string. -# Example: mongodb://user:password@host1:port1,host2:port2/dbname?options - -mongo: - uri: '' - - # List of MongoDB server addresses. - # Used for constructing the MongoDB URI if 'uri' above is empty. - # For a standalone setup, specify the address of the single server. - # For a sharded cluster, specify the addresses of the Mongos servers. - # Example: [ '172.28.0.1:37017', '172.28.0.2:37017' ] - # Default MongoDB database name - # Maximum connection pool size - address: [ 172.28.0.1:37017 ] - database: openim_v3 - username: openIM - password: openIM123 - maxPoolSize: 100 diff --git a/go.mod b/go.mod index 71433ed82..3a2ebc57b 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/golang/protobuf v1.5.4 // indirect github.com/google/uuid v1.6.0 github.com/jinzhu/copier v0.4.0 // indirect - github.com/pkg/errors v0.9.1 + github.com/pkg/errors v0.9.1 // indirect google.golang.org/grpc v1.62.1 google.golang.org/protobuf v1.34.2 gopkg.in/yaml.v3 v3.0.1 // indirect @@ -33,13 +33,8 @@ require ( github.com/spf13/cobra v1.8.0 github.com/spf13/viper v1.18.2 github.com/xuri/excelize/v2 v2.8.0 - go.etcd.io/etcd/client/v3 v3.5.13 go.mongodb.org/mongo-driver v1.14.0 - go.uber.org/zap v1.27.0 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df - k8s.io/api v0.31.2 - k8s.io/apimachinery v0.31.2 - k8s.io/client-go v0.31.2 ) require ( @@ -124,7 +119,9 @@ require ( github.com/yusufpapurcu/wmi v1.2.4 // indirect go.etcd.io/etcd/api/v3 v3.5.13 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.13 // indirect + go.etcd.io/etcd/client/v3 v3.5.13 // indirect go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/crypto v0.24.0 // indirect golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect @@ -142,6 +139,9 @@ require ( gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect + k8s.io/api v0.31.2 // indirect + k8s.io/apimachinery v0.31.2 // indirect + k8s.io/client-go v0.31.2 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect From 700a321fb9aa2b7cace8c630e733b56787d9f70b Mon Sep 17 00:00:00 2001 From: icey-yu <119291641+icey-yu@users.noreply.github.com> Date: Fri, 27 Dec 2024 16:23:01 +0800 Subject: [PATCH 21/36] feat: config center (#619) * feat: config center * feat: config center --- internal/api/admin/config_manager.go | 202 ++++++++++++++++++ internal/api/admin/start.go | 84 +++++++- internal/api/chat/start.go | 79 +++++-- pkg/common/apistruct/config_manager.go | 16 ++ pkg/common/cmd/admin_api.go | 18 +- pkg/common/cmd/admin_rpc.go | 20 +- pkg/common/cmd/chat_api.go | 7 +- pkg/common/cmd/chat_rpc.go | 20 +- pkg/common/cmd/root.go | 92 +++++++- pkg/common/config/config.go | 51 +++++ pkg/common/{cmd/constant.go => config/env.go} | 22 +- pkg/common/kdisc/etcd/config_manager.go | 111 ++++++++++ pkg/common/startrpc/start.go | 25 +-- tools/attribute-to-credential/main.go | 3 +- tools/check-component/main.go | 9 +- 15 files changed, 669 insertions(+), 90 deletions(-) create mode 100644 internal/api/admin/config_manager.go create mode 100644 pkg/common/apistruct/config_manager.go rename pkg/common/{cmd/constant.go => config/env.go} (56%) create mode 100644 pkg/common/kdisc/etcd/config_manager.go diff --git a/internal/api/admin/config_manager.go b/internal/api/admin/config_manager.go new file mode 100644 index 000000000..414965d08 --- /dev/null +++ b/internal/api/admin/config_manager.go @@ -0,0 +1,202 @@ +package admin + +import ( + "encoding/json" + "reflect" + "strconv" + "time" + + "github.com/gin-gonic/gin" + "github.com/openimsdk/chat/pkg/common/apistruct" + "github.com/openimsdk/chat/pkg/common/config" + "github.com/openimsdk/chat/pkg/common/kdisc" + "github.com/openimsdk/chat/pkg/common/kdisc/etcd" + "github.com/openimsdk/chat/version" + "github.com/openimsdk/tools/apiresp" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/utils/runtimeenv" + clientv3 "go.etcd.io/etcd/client/v3" +) + +type ConfigManager struct { + config *config.AllConfig + client *clientv3.Client + configPath string + runtimeEnv string +} + +func NewConfigManager(cfg *config.AllConfig, client *clientv3.Client, configPath string, runtimeEnv string) *ConfigManager { + return &ConfigManager{ + config: cfg, + client: client, + configPath: configPath, + runtimeEnv: runtimeEnv, + } +} + +func (cm *ConfigManager) GetConfig(c *gin.Context) { + var req apistruct.GetConfigReq + if err := c.BindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) + return + } + conf := cm.config.Name2Config(req.ConfigName) + if conf == nil { + apiresp.GinError(c, errs.ErrArgs.WithDetail("config name not found").Wrap()) + return + } + b, err := json.Marshal(conf) + if err != nil { + apiresp.GinError(c, err) + return + } + apiresp.GinSuccess(c, string(b)) +} + +func (cm *ConfigManager) GetConfigList(c *gin.Context) { + var resp apistruct.GetConfigListResp + resp.ConfigNames = cm.config.GetConfigNames() + resp.Environment = runtimeenv.PrintRuntimeEnvironment() + resp.Version = version.Version + + apiresp.GinSuccess(c, resp) +} + +func (cm *ConfigManager) SetConfig(c *gin.Context) { + if cm.config.Discovery.Enable != kdisc.ETCDCONST { + apiresp.GinError(c, errs.New("only etcd support set config").Wrap()) + return + } + var req apistruct.SetConfigReq + if err := c.BindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) + return + } + var err error + switch req.ConfigName { + case config.DiscoveryConfigFileName: + err = compareAndSave[config.Discovery](c, cm.config.Name2Config(req.ConfigName), &req, cm.client) + case config.LogConfigFileName: + err = compareAndSave[config.Log](c, cm.config.Name2Config(req.ConfigName), &req, cm.client) + case config.MongodbConfigFileName: + err = compareAndSave[config.Mongo](c, cm.config.Name2Config(req.ConfigName), &req, cm.client) + case config.ChatAPIAdminCfgFileName: + err = compareAndSave[config.API](c, cm.config.Name2Config(req.ConfigName), &req, cm.client) + case config.ChatAPIChatCfgFileName: + err = compareAndSave[config.API](c, cm.config.Name2Config(req.ConfigName), &req, cm.client) + case config.ChatRPCAdminCfgFileName: + err = compareAndSave[config.Admin](c, cm.config.Name2Config(req.ConfigName), &req, cm.client) + case config.ChatRPCChatCfgFileName: + err = compareAndSave[config.Chat](c, cm.config.Name2Config(req.ConfigName), &req, cm.client) + case config.ShareFileName: + err = compareAndSave[config.Share](c, cm.config.Name2Config(req.ConfigName), &req, cm.client) + case config.RedisConfigFileName: + err = compareAndSave[config.Redis](c, cm.config.Name2Config(req.ConfigName), &req, cm.client) + default: + apiresp.GinError(c, errs.ErrArgs.Wrap()) + return + } + if err != nil { + apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) + return + } + apiresp.GinSuccess(c, nil) +} + +func compareAndSave[T any](c *gin.Context, old any, req *apistruct.SetConfigReq, client *clientv3.Client) error { + conf := new(T) + err := json.Unmarshal([]byte(req.Data), &conf) + if err != nil { + return errs.ErrArgs.WithDetail(err.Error()).Wrap() + } + eq := reflect.DeepEqual(old, conf) + if eq { + return nil + } + data, err := json.Marshal(conf) + if err != nil { + return errs.ErrArgs.WithDetail(err.Error()).Wrap() + } + _, err = client.Put(c, etcd.BuildKey(req.ConfigName), string(data)) + if err != nil { + return errs.WrapMsg(err, "save to etcd failed") + } + return nil +} + +func (cm *ConfigManager) ResetConfig(c *gin.Context) { + go cm.resetConfig(c) + apiresp.GinSuccess(c, nil) +} + +func (cm *ConfigManager) resetConfig(c *gin.Context) { + txn := cm.client.Txn(c) + type initConf struct { + old any + new any + isChanged bool + } + configMap := map[string]*initConf{ + config.DiscoveryConfigFileName: {old: &cm.config.Discovery, new: new(config.Discovery)}, + config.LogConfigFileName: {old: &cm.config.Log, new: new(config.Log)}, + config.MongodbConfigFileName: {old: &cm.config.Mongo, new: new(config.Mongo)}, + config.ChatAPIAdminCfgFileName: {old: &cm.config.AdminAPI, new: new(config.API)}, + config.ChatAPIChatCfgFileName: {old: &cm.config.ChatAPI, new: new(config.API)}, + config.ChatRPCAdminCfgFileName: {old: &cm.config.Admin, new: new(config.Admin)}, + config.ChatRPCChatCfgFileName: {old: &cm.config.Chat, new: new(config.Chat)}, + config.RedisConfigFileName: {old: &cm.config.Redis, new: new(config.Redis)}, + config.ShareFileName: {old: &cm.config.Share, new: new(config.Share)}, + } + + changedKeys := make([]string, 0, len(configMap)) + for k, v := range configMap { + err := config.Load( + cm.configPath, + k, + config.EnvPrefixMap[k], + cm.runtimeEnv, + v.new, + ) + if err != nil { + log.ZError(c, "load config failed", err) + continue + } + v.isChanged = reflect.DeepEqual(v.old, v.new) + if !v.isChanged { + changedKeys = append(changedKeys, k) + } + } + + ops := make([]clientv3.Op, 0) + for _, k := range changedKeys { + data, err := json.Marshal(configMap[k].new) + if err != nil { + log.ZError(c, "marshal config failed", err) + continue + } + ops = append(ops, clientv3.OpPut(etcd.BuildKey(k), string(data))) + } + if len(ops) > 0 { + txn.Then(ops...) + _, err := txn.Commit() + if err != nil { + log.ZError(c, "commit etcd txn failed", err) + return + } + } +} + +func (cm *ConfigManager) Restart(c *gin.Context) { + go cm.restart(c) + apiresp.GinSuccess(c, nil) +} + +func (cm *ConfigManager) restart(c *gin.Context) { + time.Sleep(time.Millisecond * 200) // wait for Restart http call return + t := time.Now().Unix() + _, err := cm.client.Put(c, etcd.BuildKey(etcd.RestartKey), strconv.Itoa(int(t))) + if err != nil { + log.ZError(c, "restart etcd put key failed", err) + } +} diff --git a/internal/api/admin/start.go b/internal/api/admin/start.go index 32d2623b9..4740e3aa4 100644 --- a/internal/api/admin/start.go +++ b/internal/api/admin/start.go @@ -2,7 +2,13 @@ package admin import ( "context" + "errors" "fmt" + "net/http" + "os" + "os/signal" + "syscall" + "time" "github.com/gin-gonic/gin" chatmw "github.com/openimsdk/chat/internal/api/mw" @@ -10,24 +16,26 @@ import ( "github.com/openimsdk/chat/pkg/common/config" "github.com/openimsdk/chat/pkg/common/imapi" "github.com/openimsdk/chat/pkg/common/kdisc" + disetcd "github.com/openimsdk/chat/pkg/common/kdisc/etcd" adminclient "github.com/openimsdk/chat/pkg/protocol/admin" chatclient "github.com/openimsdk/chat/pkg/protocol/chat" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/discovery/etcd" "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/mw" + "github.com/openimsdk/tools/system/program" "github.com/openimsdk/tools/utils/datautil" + "github.com/openimsdk/tools/utils/runtimeenv" + clientv3 "go.etcd.io/etcd/client/v3" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" - - "github.com/openimsdk/tools/utils/runtimeenv" ) type Config struct { - ApiConfig config.API - - Discovery config.Discovery - Share config.Share + *config.AllConfig RuntimeEnv string + ConfigPath string } func Start(ctx context.Context, index int, config *Config) error { @@ -36,7 +44,7 @@ func Start(ctx context.Context, index int, config *Config) error { if len(config.Share.ChatAdmin) == 0 { return errs.New("share chat admin not configured") } - apiPort, err := datautil.GetElemByIndex(config.ApiConfig.Api.Ports, index) + apiPort, err := datautil.GetElemByIndex(config.AdminAPI.Api.Ports, index) if err != nil { return err } @@ -66,11 +74,51 @@ func Start(ctx context.Context, index int, config *Config) error { gin.SetMode(gin.ReleaseMode) engine := gin.New() engine.Use(gin.Recovery(), mw.CorsHandler(), mw.GinParseOperationID()) - SetAdminRoute(engine, adminApi, mwApi) - return engine.Run(fmt.Sprintf(":%d", apiPort)) + SetAdminRoute(engine, adminApi, mwApi, config, client) + + if config.Discovery.Enable == kdisc.ETCDCONST { + cm := disetcd.NewConfigManager(client.(*etcd.SvcDiscoveryRegistryImpl).GetClient(), config.GetConfigNames()) + cm.Watch(ctx) + } + var ( + netDone = make(chan struct{}, 1) + netErr error + ) + server := http.Server{Addr: fmt.Sprintf(":%d", apiPort), Handler: engine} + go func() { + err = server.ListenAndServe() + if err != nil && !errors.Is(err, http.ErrServerClosed) { + netErr = errs.WrapMsg(err, fmt.Sprintf("api start err: %s", server.Addr)) + netDone <- struct{}{} + } + }() + shutdown := func() error { + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + err := server.Shutdown(ctx) + if err != nil { + return errs.WrapMsg(err, "shutdown err") + } + return nil + } + disetcd.RegisterShutDown(shutdown) + + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, syscall.SIGTERM) + select { + case <-sigs: + program.SIGTERMExit() + if err := shutdown(); err != nil { + return err + } + case <-netDone: + close(netDone) + return netErr + } + return nil } -func SetAdminRoute(router gin.IRouter, admin *Api, mw *chatmw.MW) { +func SetAdminRoute(router gin.IRouter, admin *Api, mw *chatmw.MW, cfg *Config, client discovery.SvcDiscoveryRegistry) { adminRouterGroup := router.Group("/account") adminRouterGroup.POST("/login", admin.AdminLogin) // Login @@ -149,4 +197,20 @@ func SetAdminRoute(router gin.IRouter, admin *Api, mw *chatmw.MW) { applicationGroup.POST("/delete_version", mw.CheckAdmin, admin.DeleteApplicationVersion) applicationGroup.POST("/latest_version", admin.LatestApplicationVersion) applicationGroup.POST("/page_versions", admin.PageApplicationVersion) + + var etcdClient *clientv3.Client + if cfg.Discovery.Enable == kdisc.ETCDCONST { + etcdClient = client.(*etcd.SvcDiscoveryRegistryImpl).GetClient() + } + cm := NewConfigManager(cfg.AllConfig, etcdClient, cfg.ConfigPath, cfg.RuntimeEnv) + { + configGroup := router.Group("/config", mw.CheckAdmin) + configGroup.POST("/get_config_list", cm.GetConfigList) + configGroup.POST("/get_config", cm.GetConfig) + configGroup.POST("/set_config", cm.SetConfig) + configGroup.POST("/reset_config", cm.ResetConfig) + } + { + router.POST("/restart", mw.CheckAdmin, cm.Restart) + } } diff --git a/internal/api/chat/start.go b/internal/api/chat/start.go index 57dc73ce1..da83468ee 100644 --- a/internal/api/chat/start.go +++ b/internal/api/chat/start.go @@ -2,7 +2,13 @@ package chat import ( "context" + "errors" "fmt" + "net/http" + "os" + "os/signal" + "syscall" + "time" "github.com/gin-gonic/gin" chatmw "github.com/openimsdk/chat/internal/api/mw" @@ -10,10 +16,13 @@ import ( "github.com/openimsdk/chat/pkg/common/config" "github.com/openimsdk/chat/pkg/common/imapi" "github.com/openimsdk/chat/pkg/common/kdisc" + disetcd "github.com/openimsdk/chat/pkg/common/kdisc/etcd" adminclient "github.com/openimsdk/chat/pkg/protocol/admin" chatclient "github.com/openimsdk/chat/pkg/protocol/chat" + "github.com/openimsdk/tools/discovery/etcd" "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/mw" + "github.com/openimsdk/tools/system/program" "github.com/openimsdk/tools/utils/datautil" "github.com/openimsdk/tools/utils/runtimeenv" "google.golang.org/grpc" @@ -28,36 +37,36 @@ type Config struct { RuntimeEnv string } -func Start(ctx context.Context, index int, config *Config) error { - config.RuntimeEnv = runtimeenv.PrintRuntimeEnvironment() +func Start(ctx context.Context, index int, cfg *Config) error { + cfg.RuntimeEnv = runtimeenv.PrintRuntimeEnvironment() - if len(config.Share.ChatAdmin) == 0 { + if len(cfg.Share.ChatAdmin) == 0 { return errs.New("share chat admin not configured") } - apiPort, err := datautil.GetElemByIndex(config.ApiConfig.Api.Ports, index) + apiPort, err := datautil.GetElemByIndex(cfg.ApiConfig.Api.Ports, index) if err != nil { return err } - client, err := kdisc.NewDiscoveryRegister(&config.Discovery, config.RuntimeEnv) + client, err := kdisc.NewDiscoveryRegister(&cfg.Discovery, cfg.RuntimeEnv) if err != nil { return err } - chatConn, err := client.GetConn(ctx, config.Discovery.RpcService.Chat, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) + chatConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Chat, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) if err != nil { return err } - adminConn, err := client.GetConn(ctx, config.Discovery.RpcService.Admin, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) + adminConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Admin, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) if err != nil { return err } chatClient := chatclient.NewChatClient(chatConn) adminClient := adminclient.NewAdminClient(adminConn) - im := imapi.New(config.Share.OpenIM.ApiURL, config.Share.OpenIM.Secret, config.Share.OpenIM.AdminUserID) + im := imapi.New(cfg.Share.OpenIM.ApiURL, cfg.Share.OpenIM.Secret, cfg.Share.OpenIM.AdminUserID) base := util.Api{ - ImUserID: config.Share.OpenIM.AdminUserID, - ProxyHeader: config.Share.ProxyHeader, - ChatAdminUserID: config.Share.ChatAdmin[0], + ImUserID: cfg.Share.OpenIM.AdminUserID, + ProxyHeader: cfg.Share.ProxyHeader, + ChatAdminUserID: cfg.Share.ChatAdmin[0], } adminApi := New(chatClient, adminClient, im, &base) mwApi := chatmw.New(adminClient) @@ -65,7 +74,53 @@ func Start(ctx context.Context, index int, config *Config) error { engine := gin.New() engine.Use(gin.Recovery(), mw.CorsHandler(), mw.GinParseOperationID()) SetChatRoute(engine, adminApi, mwApi) - return engine.Run(fmt.Sprintf(":%d", apiPort)) + + var ( + netDone = make(chan struct{}, 1) + netErr error + ) + server := http.Server{Addr: fmt.Sprintf(":%d", apiPort), Handler: engine} + go func() { + err = server.ListenAndServe() + if err != nil && !errors.Is(err, http.ErrServerClosed) { + netErr = errs.WrapMsg(err, fmt.Sprintf("api start err: %s", server.Addr)) + netDone <- struct{}{} + } + }() + if cfg.Discovery.Enable == kdisc.ETCDCONST { + cm := disetcd.NewConfigManager(client.(*etcd.SvcDiscoveryRegistryImpl).GetClient(), + []string{ + config.ChatAPIChatCfgFileName, + config.DiscoveryConfigFileName, + config.ShareFileName, + }, + ) + cm.Watch(ctx) + } + shutdown := func() error { + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + err := server.Shutdown(ctx) + if err != nil { + return errs.WrapMsg(err, "shutdown err") + } + return nil + } + disetcd.RegisterShutDown(shutdown) + + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, syscall.SIGTERM) + select { + case <-sigs: + program.SIGTERMExit() + if err := shutdown(); err != nil { + return err + } + case <-netDone: + close(netDone) + return netErr + } + return nil } func SetChatRoute(router gin.IRouter, chat *Api, mw *chatmw.MW) { diff --git a/pkg/common/apistruct/config_manager.go b/pkg/common/apistruct/config_manager.go new file mode 100644 index 000000000..84b8fb36b --- /dev/null +++ b/pkg/common/apistruct/config_manager.go @@ -0,0 +1,16 @@ +package apistruct + +type GetConfigReq struct { + ConfigName string `json:"configName"` +} + +type GetConfigListResp struct { + Environment string `json:"environment"` + Version string `json:"version"` + ConfigNames []string `json:"configNames"` +} + +type SetConfigReq struct { + ConfigName string `json:"configName"` + Data string `json:"data"` +} diff --git a/pkg/common/cmd/admin_api.go b/pkg/common/cmd/admin_api.go index 47b2469f9..e3c31613e 100644 --- a/pkg/common/cmd/admin_api.go +++ b/pkg/common/cmd/admin_api.go @@ -2,6 +2,7 @@ package cmd import ( "context" + "github.com/openimsdk/chat/internal/api/admin" "github.com/openimsdk/chat/pkg/common/config" "github.com/openimsdk/tools/system/program" @@ -16,15 +17,24 @@ type AdminApiCmd struct { } func NewAdminApiCmd() *AdminApiCmd { - var ret AdminApiCmd + ret := AdminApiCmd{apiConfig: admin.Config{ + AllConfig: &config.AllConfig{}, + }} ret.configMap = map[string]any{ - ShareFileName: &ret.apiConfig.Share, - ChatAPIAdminCfgFileName: &ret.apiConfig.ApiConfig, - DiscoveryConfigFileName: &ret.apiConfig.Discovery, + config.DiscoveryConfigFileName: &ret.apiConfig.Discovery, + config.LogConfigFileName: &ret.apiConfig.Log, + config.MongodbConfigFileName: &ret.apiConfig.Mongo, + config.ChatAPIAdminCfgFileName: &ret.apiConfig.AdminAPI, + config.ChatAPIChatCfgFileName: &ret.apiConfig.ChatAPI, + config.ChatRPCAdminCfgFileName: &ret.apiConfig.Admin, + config.ChatRPCChatCfgFileName: &ret.apiConfig.Chat, + config.RedisConfigFileName: &ret.apiConfig.Redis, + config.ShareFileName: &ret.apiConfig.Share, } ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap)) ret.ctx = context.WithValue(context.Background(), "version", config.Version) ret.Command.RunE = func(cmd *cobra.Command, args []string) error { + ret.apiConfig.ConfigPath = ret.configPath return ret.runE() } return &ret diff --git a/pkg/common/cmd/admin_rpc.go b/pkg/common/cmd/admin_rpc.go index 3cea0c2f7..e46c929a3 100644 --- a/pkg/common/cmd/admin_rpc.go +++ b/pkg/common/cmd/admin_rpc.go @@ -34,11 +34,11 @@ type AdminRpcCmd struct { func NewAdminRpcCmd() *AdminRpcCmd { var ret AdminRpcCmd ret.configMap = map[string]any{ - ChatRPCAdminCfgFileName: &ret.adminConfig.RpcConfig, - RedisConfigFileName: &ret.adminConfig.RedisConfig, - DiscoveryConfigFileName: &ret.adminConfig.Discovery, - MongodbConfigFileName: &ret.adminConfig.MongodbConfig, - ShareFileName: &ret.adminConfig.Share, + config.ChatRPCAdminCfgFileName: &ret.adminConfig.RpcConfig, + config.RedisConfigFileName: &ret.adminConfig.RedisConfig, + config.DiscoveryConfigFileName: &ret.adminConfig.Discovery, + config.MongodbConfigFileName: &ret.adminConfig.MongodbConfig, + config.ShareFileName: &ret.adminConfig.Share, } ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap)) ret.ctx = context.WithValue(context.Background(), "version", config.Version) @@ -55,5 +55,13 @@ func (a *AdminRpcCmd) Exec() error { func (a *AdminRpcCmd) runE() error { return startrpc.Start(a.ctx, &a.adminConfig.Discovery, a.adminConfig.RpcConfig.RPC.ListenIP, a.adminConfig.RpcConfig.RPC.RegisterIP, a.adminConfig.RpcConfig.RPC.Ports, - a.Index(), a.adminConfig.Discovery.RpcService.Admin, &a.adminConfig.Share, &a.adminConfig, admin.Start) + a.Index(), a.adminConfig.Discovery.RpcService.Admin, &a.adminConfig.Share, &a.adminConfig, + []string{ + config.ChatRPCAdminCfgFileName, + config.RedisConfigFileName, + config.DiscoveryConfigFileName, + config.MongodbConfigFileName, + config.ShareFileName, + }, + admin.Start) } diff --git a/pkg/common/cmd/chat_api.go b/pkg/common/cmd/chat_api.go index 5e85f11c2..9c8da44e3 100644 --- a/pkg/common/cmd/chat_api.go +++ b/pkg/common/cmd/chat_api.go @@ -2,6 +2,7 @@ package cmd import ( "context" + "github.com/openimsdk/chat/internal/api/chat" "github.com/openimsdk/chat/pkg/common/config" "github.com/openimsdk/tools/system/program" @@ -18,9 +19,9 @@ type ChatApiCmd struct { func NewChatApiCmd() *ChatApiCmd { var ret ChatApiCmd ret.configMap = map[string]any{ - ShareFileName: &ret.apiConfig.Share, - ChatAPIChatCfgFileName: &ret.apiConfig.ApiConfig, - DiscoveryConfigFileName: &ret.apiConfig.Discovery, + config.ShareFileName: &ret.apiConfig.Share, + config.ChatAPIChatCfgFileName: &ret.apiConfig.ApiConfig, + config.DiscoveryConfigFileName: &ret.apiConfig.Discovery, } ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap)) ret.ctx = context.WithValue(context.Background(), "version", config.Version) diff --git a/pkg/common/cmd/chat_rpc.go b/pkg/common/cmd/chat_rpc.go index 9bc5e72f6..7f4bd859b 100644 --- a/pkg/common/cmd/chat_rpc.go +++ b/pkg/common/cmd/chat_rpc.go @@ -34,11 +34,11 @@ type ChatRpcCmd struct { func NewChatRpcCmd() *ChatRpcCmd { var ret ChatRpcCmd ret.configMap = map[string]any{ - ChatRPCChatCfgFileName: &ret.chatConfig.RpcConfig, - RedisConfigFileName: &ret.chatConfig.RedisConfig, - DiscoveryConfigFileName: &ret.chatConfig.Discovery, - MongodbConfigFileName: &ret.chatConfig.MongodbConfig, - ShareFileName: &ret.chatConfig.Share, + config.ChatRPCChatCfgFileName: &ret.chatConfig.RpcConfig, + config.RedisConfigFileName: &ret.chatConfig.RedisConfig, + config.DiscoveryConfigFileName: &ret.chatConfig.Discovery, + config.MongodbConfigFileName: &ret.chatConfig.MongodbConfig, + config.ShareFileName: &ret.chatConfig.Share, } ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap)) ret.ctx = context.WithValue(context.Background(), "version", config.Version) @@ -55,5 +55,13 @@ func (a *ChatRpcCmd) Exec() error { func (a *ChatRpcCmd) runE() error { return startrpc.Start(a.ctx, &a.chatConfig.Discovery, a.chatConfig.RpcConfig.RPC.ListenIP, a.chatConfig.RpcConfig.RPC.RegisterIP, a.chatConfig.RpcConfig.RPC.Ports, - a.Index(), a.chatConfig.Discovery.RpcService.Chat, &a.chatConfig.Share, &a.chatConfig, chat.Start) + a.Index(), a.chatConfig.Discovery.RpcService.Chat, &a.chatConfig.Share, &a.chatConfig, + []string{ + config.ChatRPCChatCfgFileName, + config.RedisConfigFileName, + config.DiscoveryConfigFileName, + config.MongodbConfigFileName, + config.ShareFileName, + }, + chat.Start) } diff --git a/pkg/common/cmd/root.go b/pkg/common/cmd/root.go index 4cea0a16d..6521e551b 100644 --- a/pkg/common/cmd/root.go +++ b/pkg/common/cmd/root.go @@ -15,10 +15,16 @@ package cmd import ( + "context" + "encoding/json" "fmt" "github.com/openimsdk/chat/pkg/common/config" + "github.com/openimsdk/chat/pkg/common/kdisc" + disetcd "github.com/openimsdk/chat/pkg/common/kdisc/etcd" "github.com/openimsdk/chat/version" + "github.com/openimsdk/tools/discovery/etcd" + clientv3 "go.etcd.io/etcd/client/v3" "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/log" @@ -34,6 +40,8 @@ type RootCmd struct { prometheusPort int log config.Log index int + configPath string + etcdClient *clientv3.Client } func (r *RootCmd) Index() int { @@ -71,19 +79,43 @@ func NewRootCmd(processName string, opts ...func(*CmdOpts)) *RootCmd { SilenceUsage: true, SilenceErrors: false, } - cmd.Flags().StringP(FlagConf, "c", "", "path of config directory") - cmd.Flags().IntP(FlagTransferIndex, "i", 0, "process startup sequence number") + cmd.Flags().StringP(config.FlagConf, "c", "", "path of config directory") + cmd.Flags().IntP(config.FlagTransferIndex, "i", 0, "process startup sequence number") rootCmd.Command = cmd return rootCmd } +func (r *RootCmd) initEtcd() error { + configDirectory, _, err := r.getFlag(&r.Command) + if err != nil { + return err + } + disConfig := config.Discovery{} + env := runtimeenv.PrintRuntimeEnvironment() + err = config.Load(configDirectory, config.DiscoveryConfigFileName, config.EnvPrefixMap[config.DiscoveryConfigFileName], + env, &disConfig) + if err != nil { + return err + } + if disConfig.Enable == kdisc.ETCDCONST { + discov, _ := kdisc.NewDiscoveryRegister(&disConfig, env) + r.etcdClient = discov.(*etcd.SvcDiscoveryRegistryImpl).GetClient() + } + return nil +} + func (r *RootCmd) persistentPreRun(cmd *cobra.Command, opts ...func(*CmdOpts)) error { + if err := r.initEtcd(); err != nil { + return err + } cmdOpts := r.applyOptions(opts...) if err := r.initializeConfiguration(cmd, cmdOpts); err != nil { return err } - + if err := r.updateConfigFromEtcd(cmdOpts); err != nil { + return err + } if err := r.initializeLogger(cmdOpts); err != nil { return errs.WrapMsg(err, "failed to initialize logger") } @@ -96,6 +128,7 @@ func (r *RootCmd) initializeConfiguration(cmd *cobra.Command, opts *CmdOpts) err if err != nil { return err } + r.configPath = configDirectory runtimeEnv := runtimeenv.PrintRuntimeEnvironment() @@ -103,14 +136,57 @@ func (r *RootCmd) initializeConfiguration(cmd *cobra.Command, opts *CmdOpts) err //opts.configMap[ShareFileName] = StructEnvPrefix{EnvPrefix: shareEnvPrefix, ConfigStruct: &r.share} for configFileName, configStruct := range opts.configMap { err := config.Load(configDirectory, configFileName, - ConfigEnvPrefixMap[configFileName], runtimeEnv, configStruct) + config.EnvPrefixMap[configFileName], runtimeEnv, configStruct) + if err != nil { + return err + } + } + // Load common log configuration file + return config.Load(configDirectory, config.LogConfigFileName, + config.EnvPrefixMap[config.LogConfigFileName], runtimeEnv, &r.log) +} + +func (r *RootCmd) updateConfigFromEtcd(opts *CmdOpts) error { + if r.etcdClient == nil { + return nil + } + + update := func(configFileName string, configStruct any) error { + ctx := context.TODO() + key := disetcd.BuildKey(configFileName) + etcdRes, err := r.etcdClient.Get(ctx, key) if err != nil { + log.ZWarn(ctx, "root cmd updateConfigFromEtcd, etcd Get err: %v", errs.Wrap(err)) + return nil + } + if etcdRes.Count == 0 { + data, err := json.Marshal(configStruct) + if err != nil { + return errs.ErrArgs.WithDetail(err.Error()).Wrap() + } + _, err = r.etcdClient.Put(ctx, disetcd.BuildKey(configFileName), string(data)) + if err != nil { + log.ZWarn(ctx, "root cmd updateConfigFromEtcd, etcd Put err: %v", errs.Wrap(err)) + } + return nil + } + err = json.Unmarshal(etcdRes.Kvs[0].Value, configStruct) + if err != nil { + return errs.WrapMsg(err, "failed to unmarshal config from etcd") + } + return nil + } + for configFileName, configStruct := range opts.configMap { + if err := update(configFileName, configStruct); err != nil { return err } } + if err := update(config.LogConfigFileName, &r.log); err != nil { + return err + } // Load common log configuration file - return config.Load(configDirectory, LogConfigFileName, - ConfigEnvPrefixMap[LogConfigFileName], runtimeEnv, &r.log) + return nil + } func (r *RootCmd) applyOptions(opts ...func(*CmdOpts)) *CmdOpts { @@ -150,11 +226,11 @@ func defaultCmdOpts() *CmdOpts { } func (r *RootCmd) getFlag(cmd *cobra.Command) (string, int, error) { - configDirectory, err := cmd.Flags().GetString(FlagConf) + configDirectory, err := cmd.Flags().GetString(config.FlagConf) if err != nil { return "", 0, errs.Wrap(err) } - index, err := cmd.Flags().GetInt(FlagTransferIndex) + index, err := cmd.Flags().GetInt(config.FlagTransferIndex) if err != nil { return "", 0, errs.Wrap(err) } diff --git a/pkg/common/config/config.go b/pkg/common/config/config.go index 4acb7ca33..53d2db26c 100644 --- a/pkg/common/config/config.go +++ b/pkg/common/config/config.go @@ -168,3 +168,54 @@ type Log struct { IsSimplify bool `mapstructure:"isSimplify"` WithStack bool `mapstructure:"withStack"` } + +type AllConfig struct { + AdminAPI API + ChatAPI API + Admin Admin + Chat Chat + Discovery Discovery + Log Log + Mongo Mongo + Redis Redis + Share Share +} + +func (a *AllConfig) Name2Config(name string) any { + switch name { + case ChatAPIAdminCfgFileName: + return a.AdminAPI + case ChatAPIChatCfgFileName: + return a.ChatAPI + case ChatRPCAdminCfgFileName: + return a.Admin + case ChatRPCChatCfgFileName: + return a.Chat + case DiscoveryConfigFileName: + return a.Discovery + case LogConfigFileName: + return a.Log + case MongodbConfigFileName: + return a.Mongo + case RedisConfigFileName: + return a.Redis + case ShareFileName: + return a.Share + default: + return nil + } +} + +func (a *AllConfig) GetConfigNames() []string { + return []string{ + ShareFileName, + RedisConfigFileName, + DiscoveryConfigFileName, + MongodbConfigFileName, + LogConfigFileName, + ChatAPIAdminCfgFileName, + ChatAPIChatCfgFileName, + ChatRPCAdminCfgFileName, + ChatRPCChatCfgFileName, + } +} diff --git a/pkg/common/cmd/constant.go b/pkg/common/config/env.go similarity index 56% rename from pkg/common/cmd/constant.go rename to pkg/common/config/env.go index b07147d69..aa3170cce 100644 --- a/pkg/common/cmd/constant.go +++ b/pkg/common/config/env.go @@ -1,18 +1,4 @@ -// Copyright © 2023 OpenIM. 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 cmd +package config import ( "strings" @@ -30,10 +16,10 @@ var ( ChatRPCChatCfgFileName = "chat-rpc-chat.yml" ) -var ConfigEnvPrefixMap map[string]string +var EnvPrefixMap map[string]string func init() { - ConfigEnvPrefixMap = make(map[string]string) + EnvPrefixMap = make(map[string]string) fileNames := []string{ ShareFileName, RedisConfigFileName, @@ -50,7 +36,7 @@ func init() { envKey := strings.TrimSuffix(strings.TrimSuffix(fileName, ".yml"), ".yaml") envKey = "CHATENV_" + envKey envKey = strings.ToUpper(strings.ReplaceAll(envKey, "-", "_")) - ConfigEnvPrefixMap[fileName] = envKey + EnvPrefixMap[fileName] = envKey } } diff --git a/pkg/common/kdisc/etcd/config_manager.go b/pkg/common/kdisc/etcd/config_manager.go new file mode 100644 index 000000000..4e4e065b8 --- /dev/null +++ b/pkg/common/kdisc/etcd/config_manager.go @@ -0,0 +1,111 @@ +package etcd + +import ( + "context" + "os" + "os/exec" + "runtime" + "sync" + "syscall" + + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/utils/datautil" + clientv3 "go.etcd.io/etcd/client/v3" +) + +const ( + ConfigKeyPrefix = "/chat/config/" + RestartKey = "restart" +) + +var ( + ShutDowns []func() error +) + +func RegisterShutDown(shutDown ...func() error) { + ShutDowns = append(ShutDowns, shutDown...) +} + +type ConfigManager struct { + client *clientv3.Client + watchConfigNames []string + lock sync.Mutex +} + +func BuildKey(s string) string { + return ConfigKeyPrefix + s +} + +func NewConfigManager(client *clientv3.Client, configNames []string) *ConfigManager { + return &ConfigManager{ + client: client, + watchConfigNames: datautil.Batch(func(s string) string { return BuildKey(s) }, append(configNames, RestartKey))} +} + +func (c *ConfigManager) Watch(ctx context.Context) { + chans := make([]clientv3.WatchChan, 0, len(c.watchConfigNames)) + for _, name := range c.watchConfigNames { + chans = append(chans, c.client.Watch(ctx, name, clientv3.WithPrefix())) + } + + doWatch := func(watchChan clientv3.WatchChan) { + for watchResp := range watchChan { + if watchResp.Err() != nil { + log.ZError(ctx, "watch err", errs.Wrap(watchResp.Err())) + continue + } + for _, event := range watchResp.Events { + if event.IsModify() { + if datautil.Contain(string(event.Kv.Key), c.watchConfigNames...) { + c.lock.Lock() + err := restartServer(ctx) + if err != nil { + log.ZError(ctx, "restart server err", err) + } + c.lock.Unlock() + } + } + } + } + } + for _, ch := range chans { + go doWatch(ch) + } +} + +func restartServer(ctx context.Context) error { + exePath, err := os.Executable() + if err != nil { + return errs.New("get executable path fail").Wrap() + } + + args := os.Args + env := os.Environ() + + cmd := exec.Command(exePath, args[1:]...) + cmd.Env = env + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Stdin = os.Stdin + + if runtime.GOOS != "windows" { + cmd.SysProcAttr = &syscall.SysProcAttr{} + } + log.ZInfo(ctx, "shutdown server") + for _, f := range ShutDowns { + if err = f(); err != nil { + log.ZError(ctx, "shutdown fail", err) + } + } + + log.ZInfo(ctx, "restart server") + err = cmd.Start() + if err != nil { + return errs.New("restart server fail").Wrap() + } + log.ZInfo(ctx, "cmd start over") + + os.Exit(0) + return nil +} diff --git a/pkg/common/startrpc/start.go b/pkg/common/startrpc/start.go index d81eb88bb..e8b98a423 100644 --- a/pkg/common/startrpc/start.go +++ b/pkg/common/startrpc/start.go @@ -1,17 +1,3 @@ -// Copyright © 2023 OpenIM. 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 startrpc import ( @@ -27,6 +13,8 @@ import ( "github.com/openimsdk/chat/pkg/common/config" "github.com/openimsdk/chat/pkg/common/kdisc" + disetcd "github.com/openimsdk/chat/pkg/common/kdisc/etcd" + "github.com/openimsdk/tools/discovery/etcd" "github.com/openimsdk/tools/utils/datautil" "github.com/openimsdk/tools/utils/runtimeenv" @@ -42,8 +30,9 @@ import ( // Start rpc server. func Start[T any](ctx context.Context, discovery *config.Discovery, listenIP, - registerIP string, rpcPorts []int, index int, rpcRegisterName string, share *config.Share, config T, rpcFn func(ctx context.Context, - config T, client discovery.SvcDiscoveryRegistry, server *grpc.Server) error, options ...grpc.ServerOption) error { + registerIP string, rpcPorts []int, index int, rpcRegisterName string, share *config.Share, config T, + watchConfigNames []string, + rpcFn func(ctx context.Context, config T, client discovery.SvcDiscoveryRegistry, server *grpc.Server) error, options ...grpc.ServerOption) error { runtimeEnv := runtimeenv.PrintRuntimeEnvironment() @@ -101,6 +90,10 @@ func Start[T any](ctx context.Context, discovery *config.Discovery, listenIP, netDone <- struct{}{} } }() + if discovery.Enable == kdisc.ETCDCONST { + cm := disetcd.NewConfigManager(client.(*etcd.SvcDiscoveryRegistryImpl).GetClient(), watchConfigNames) + cm.Watch(ctx) + } sigs := make(chan os.Signal, 1) signal.Notify(sigs, syscall.SIGTERM) diff --git a/tools/attribute-to-credential/main.go b/tools/attribute-to-credential/main.go index d55797948..08dc176c8 100644 --- a/tools/attribute-to-credential/main.go +++ b/tools/attribute-to-credential/main.go @@ -7,7 +7,6 @@ import ( "path/filepath" "github.com/openimsdk/chat/internal/rpc/chat" - "github.com/openimsdk/chat/pkg/common/cmd" "github.com/openimsdk/chat/pkg/common/config" "github.com/openimsdk/chat/pkg/common/constant" table "github.com/openimsdk/chat/pkg/common/db/table/chat" @@ -37,7 +36,7 @@ func initConfig(configDir string) (*config.Mongo, error) { runtimeEnv := runtimeenv.PrintRuntimeEnvironment() - err := config.Load(configDir, cmd.MongodbConfigFileName, cmd.ConfigEnvPrefixMap[cmd.MongodbConfigFileName], runtimeEnv, mongoConfig) + err := config.Load(configDir, config.MongodbConfigFileName, config.EnvPrefixMap[config.MongodbConfigFileName], runtimeEnv, mongoConfig) if err != nil { return nil, err } diff --git a/tools/check-component/main.go b/tools/check-component/main.go index 36f488ea3..00206abbe 100644 --- a/tools/check-component/main.go +++ b/tools/check-component/main.go @@ -21,7 +21,6 @@ import ( "path/filepath" "time" - "github.com/openimsdk/chat/pkg/common/cmd" "github.com/openimsdk/chat/pkg/common/config" "github.com/openimsdk/chat/pkg/common/imapi" "github.com/openimsdk/tools/db/mongoutil" @@ -67,21 +66,21 @@ func initConfig(configDir string) (*config.Mongo, *config.Redis, *config.Discove runtimeEnv := runtimeenv.PrintRuntimeEnvironment() - err := config.Load(configDir, cmd.MongodbConfigFileName, cmd.ConfigEnvPrefixMap[cmd.MongodbConfigFileName], runtimeEnv, mongoConfig) + err := config.Load(configDir, config.MongodbConfigFileName, config.EnvPrefixMap[config.MongodbConfigFileName], runtimeEnv, mongoConfig) if err != nil { return nil, nil, nil, nil, err } - err = config.Load(configDir, cmd.RedisConfigFileName, cmd.ConfigEnvPrefixMap[cmd.RedisConfigFileName], runtimeEnv, redisConfig) + err = config.Load(configDir, config.RedisConfigFileName, config.EnvPrefixMap[config.RedisConfigFileName], runtimeEnv, redisConfig) if err != nil { return nil, nil, nil, nil, err } - err = config.Load(configDir, cmd.DiscoveryConfigFileName, cmd.ConfigEnvPrefixMap[cmd.DiscoveryConfigFileName], runtimeEnv, discoveryConfig) + err = config.Load(configDir, config.DiscoveryConfigFileName, config.EnvPrefixMap[config.DiscoveryConfigFileName], runtimeEnv, discoveryConfig) if err != nil { return nil, nil, nil, nil, err } - err = config.Load(configDir, cmd.ShareFileName, cmd.ConfigEnvPrefixMap[cmd.ShareFileName], runtimeEnv, shareConfig) + err = config.Load(configDir, config.ShareFileName, config.EnvPrefixMap[config.ShareFileName], runtimeEnv, shareConfig) if err != nil { return nil, nil, nil, nil, err } From 89ad33b3aa45d273f8c907aa167eb64c6e7aba45 Mon Sep 17 00:00:00 2001 From: Monet Lee Date: Mon, 30 Dec 2024 11:35:04 +0800 Subject: [PATCH 22/36] build: fix uncorrect images. (#620) --- ... docker-build-and-release-services-images.yml} | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) rename .github/workflows/{build-and-release-services-images.yml => docker-build-and-release-services-images.yml} (94%) diff --git a/.github/workflows/build-and-release-services-images.yml b/.github/workflows/docker-build-and-release-services-images.yml similarity index 94% rename from .github/workflows/build-and-release-services-images.yml rename to .github/workflows/docker-build-and-release-services-images.yml index d53fd2142..ed4c7ad38 100644 --- a/.github/workflows/build-and-release-services-images.yml +++ b/.github/workflows/docker-build-and-release-services-images.yml @@ -1,4 +1,4 @@ -name: Build and release services Images +name: Build and release services Docker Images on: push: @@ -61,8 +61,8 @@ jobs: - name: Build and push Docker images run: | - ROOT_DIR="build/images" - for dir in "$ROOT_DIR"/*/; do + IMG_DIR="build/images" + for dir in "$IMG_DIR"/*/; do # Find Dockerfile or *.dockerfile in a case-insensitive manner dockerfile=$(find "$dir" -maxdepth 1 -type f \( -iname 'dockerfile' -o -iname '*.dockerfile' \) | head -n 1) @@ -72,20 +72,21 @@ jobs: # Initialize tag arguments tag_args=() - + # Read each tag and append --tag arguments while IFS= read -r tag; do tag_args+=(--tag "${{ secrets.DOCKER_USERNAME }}/$IMAGE_NAME:$tag") tag_args+=(--tag "ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME:$tag") tag_args+=(--tag "registry.cn-hangzhou.aliyuncs.com/openimsdk/$IMAGE_NAME:$tag") done <<< "${{ steps.meta.outputs.tags }}" - + # Build and push the Docker image with all tags docker buildx build --platform linux/amd64,linux/arm64 \ --file "$dockerfile" \ "${tag_args[@]}" \ - --push "$dir" + --push \ + "." else echo "No valid Dockerfile found in $dir" fi - done \ No newline at end of file + done From 6e9d420b5865ec9daf687c53fdc7c0a214ecc07e Mon Sep 17 00:00:00 2001 From: icey-yu <119291641+icey-yu@users.noreply.github.com> Date: Sat, 4 Jan 2025 20:21:41 +0800 Subject: [PATCH 23/36] feat: Add enable config center button && fix: grpc connection leakage (#621) * feat: config center * feat: config center * feat: config etcd conn * fix: call err * fix: config --- go.mod | 4 +- go.sum | 4 +- internal/api/admin/admin.go | 79 +++++++++++++------------ internal/api/admin/config_manager.go | 78 ++++++++++++++++++++---- internal/api/admin/start.go | 4 +- internal/api/chat/chat.go | 22 +++---- internal/api/chat/start.go | 3 +- pkg/common/apistruct/config_manager.go | 8 +++ pkg/common/cmd/admin_rpc.go | 3 +- pkg/common/cmd/chat_rpc.go | 3 +- pkg/common/cmd/root.go | 22 ++++++- pkg/common/kdisc/discoveryregister.go | 3 +- pkg/common/kdisc/etcd/config_manager.go | 5 -- pkg/common/kdisc/etcd/const.go | 9 +++ pkg/common/startrpc/start.go | 4 +- 15 files changed, 172 insertions(+), 79 deletions(-) create mode 100644 pkg/common/kdisc/etcd/const.go diff --git a/go.mod b/go.mod index 3a2ebc57b..74f4f05ff 100644 --- a/go.mod +++ b/go.mod @@ -28,11 +28,12 @@ require ( github.com/mitchellh/mapstructure v1.5.0 github.com/openimsdk/gomake v0.0.14-alpha.5 github.com/openimsdk/protocol v0.0.72 - github.com/openimsdk/tools v0.0.50-alpha.56 + github.com/openimsdk/tools v0.0.50-alpha.64 github.com/redis/go-redis/v9 v9.5.1 github.com/spf13/cobra v1.8.0 github.com/spf13/viper v1.18.2 github.com/xuri/excelize/v2 v2.8.0 + go.etcd.io/etcd/client/v3 v3.5.13 go.mongodb.org/mongo-driver v1.14.0 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df ) @@ -119,7 +120,6 @@ require ( github.com/yusufpapurcu/wmi v1.2.4 // indirect go.etcd.io/etcd/api/v3 v3.5.13 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.13 // indirect - go.etcd.io/etcd/client/v3 v3.5.13 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/arch v0.3.0 // indirect diff --git a/go.sum b/go.sum index a4ec31003..76b85930f 100644 --- a/go.sum +++ b/go.sum @@ -217,8 +217,8 @@ github.com/openimsdk/gomake v0.0.14-alpha.5 h1:VY9c5x515lTfmdhhPjMvR3BBRrRquAUCF github.com/openimsdk/gomake v0.0.14-alpha.5/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI= github.com/openimsdk/protocol v0.0.72 h1:K+vslwaR7lDXyBzb07UuEQITaqsgighz7NyXVIWsu6A= github.com/openimsdk/protocol v0.0.72/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8= -github.com/openimsdk/tools v0.0.50-alpha.56 h1:22y0s3IPqgUYrO+r93H8Iq2oW71D5SUe88lkA0asEhU= -github.com/openimsdk/tools v0.0.50-alpha.56/go.mod h1:muCtxguNJv8lFwLei27UASu2Nvg4ERSeN0R4K5tivk0= +github.com/openimsdk/tools v0.0.50-alpha.64 h1:KmtE8V2K8atQJJg1xq2ySSrPQyf8ldwk8fw6jRnsxCw= +github.com/openimsdk/tools v0.0.50-alpha.64/go.mod h1:B+oqV0zdewN7OiEHYJm+hW+8/Te7B8tHHgD8rK5ZLZk= github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pion/datachannel v1.5.5 h1:10ef4kwdjije+M9d7Xm9im2Y3O6A6ccQb0zcqZcJew8= diff --git a/internal/api/admin/admin.go b/internal/api/admin/admin.go index b3b3ee395..c54c51581 100644 --- a/internal/api/admin/admin.go +++ b/internal/api/admin/admin.go @@ -125,15 +125,15 @@ func (o *Api) AdminUpdateInfo(c *gin.Context) { } func (o *Api) AdminInfo(c *gin.Context) { - a2r.Call(admin.AdminClient.GetAdminInfo, o.adminClient, c) + a2r.Call(c, admin.AdminClient.GetAdminInfo, o.adminClient) } func (o *Api) ChangeAdminPassword(c *gin.Context) { - a2r.Call(admin.AdminClient.ChangeAdminPassword, o.adminClient, c) + a2r.Call(c, admin.AdminClient.ChangeAdminPassword, o.adminClient) } func (o *Api) AddAdminAccount(c *gin.Context) { - a2r.Call(admin.AdminClient.AddAdminAccount, o.adminClient, c) + a2r.Call(c, admin.AdminClient.AddAdminAccount, o.adminClient) } func (o *Api) AddUserAccount(c *gin.Context) { @@ -164,27 +164,27 @@ func (o *Api) AddUserAccount(c *gin.Context) { } func (o *Api) DelAdminAccount(c *gin.Context) { - a2r.Call(admin.AdminClient.DelAdminAccount, o.adminClient, c) + a2r.Call(c, admin.AdminClient.DelAdminAccount, o.adminClient) } func (o *Api) SearchAdminAccount(c *gin.Context) { - a2r.Call(admin.AdminClient.SearchAdminAccount, o.adminClient, c) + a2r.Call(c, admin.AdminClient.SearchAdminAccount, o.adminClient) } func (o *Api) AddDefaultFriend(c *gin.Context) { - a2r.Call(admin.AdminClient.AddDefaultFriend, o.adminClient, c) + a2r.Call(c, admin.AdminClient.AddDefaultFriend, o.adminClient) } func (o *Api) DelDefaultFriend(c *gin.Context) { - a2r.Call(admin.AdminClient.DelDefaultFriend, o.adminClient, c) + a2r.Call(c, admin.AdminClient.DelDefaultFriend, o.adminClient) } func (o *Api) SearchDefaultFriend(c *gin.Context) { - a2r.Call(admin.AdminClient.SearchDefaultFriend, o.adminClient, c) + a2r.Call(c, admin.AdminClient.SearchDefaultFriend, o.adminClient) } func (o *Api) FindDefaultFriend(c *gin.Context) { - a2r.Call(admin.AdminClient.FindDefaultFriend, o.adminClient, c) + a2r.Call(c, admin.AdminClient.FindDefaultFriend, o.adminClient) } func (o *Api) AddDefaultGroup(c *gin.Context) { @@ -218,11 +218,11 @@ func (o *Api) AddDefaultGroup(c *gin.Context) { } func (o *Api) DelDefaultGroup(c *gin.Context) { - a2r.Call(admin.AdminClient.DelDefaultGroup, o.adminClient, c) + a2r.Call(c, admin.AdminClient.DelDefaultGroup, o.adminClient) } func (o *Api) FindDefaultGroup(c *gin.Context) { - a2r.Call(admin.AdminClient.FindDefaultGroup, o.adminClient, c) + a2r.Call(c, admin.AdminClient.FindDefaultGroup, o.adminClient) } func (o *Api) SearchDefaultGroup(c *gin.Context) { @@ -269,47 +269,47 @@ func (o *Api) SearchDefaultGroup(c *gin.Context) { } func (o *Api) AddInvitationCode(c *gin.Context) { - a2r.Call(admin.AdminClient.AddInvitationCode, o.adminClient, c) + a2r.Call(c, admin.AdminClient.AddInvitationCode, o.adminClient) } func (o *Api) GenInvitationCode(c *gin.Context) { - a2r.Call(admin.AdminClient.GenInvitationCode, o.adminClient, c) + a2r.Call(c, admin.AdminClient.GenInvitationCode, o.adminClient) } func (o *Api) DelInvitationCode(c *gin.Context) { - a2r.Call(admin.AdminClient.DelInvitationCode, o.adminClient, c) + a2r.Call(c, admin.AdminClient.DelInvitationCode, o.adminClient) } func (o *Api) SearchInvitationCode(c *gin.Context) { - a2r.Call(admin.AdminClient.SearchInvitationCode, o.adminClient, c) + a2r.Call(c, admin.AdminClient.SearchInvitationCode, o.adminClient) } func (o *Api) AddUserIPLimitLogin(c *gin.Context) { - a2r.Call(admin.AdminClient.AddUserIPLimitLogin, o.adminClient, c) + a2r.Call(c, admin.AdminClient.AddUserIPLimitLogin, o.adminClient) } func (o *Api) SearchUserIPLimitLogin(c *gin.Context) { - a2r.Call(admin.AdminClient.SearchUserIPLimitLogin, o.adminClient, c) + a2r.Call(c, admin.AdminClient.SearchUserIPLimitLogin, o.adminClient) } func (o *Api) DelUserIPLimitLogin(c *gin.Context) { - a2r.Call(admin.AdminClient.DelUserIPLimitLogin, o.adminClient, c) + a2r.Call(c, admin.AdminClient.DelUserIPLimitLogin, o.adminClient) } func (o *Api) SearchIPForbidden(c *gin.Context) { - a2r.Call(admin.AdminClient.SearchIPForbidden, o.adminClient, c) + a2r.Call(c, admin.AdminClient.SearchIPForbidden, o.adminClient) } func (o *Api) AddIPForbidden(c *gin.Context) { - a2r.Call(admin.AdminClient.AddIPForbidden, o.adminClient, c) + a2r.Call(c, admin.AdminClient.AddIPForbidden, o.adminClient) } func (o *Api) DelIPForbidden(c *gin.Context) { - a2r.Call(admin.AdminClient.DelIPForbidden, o.adminClient, c) + a2r.Call(c, admin.AdminClient.DelIPForbidden, o.adminClient) } func (o *Api) ParseToken(c *gin.Context) { - a2r.Call(admin.AdminClient.ParseToken, o.adminClient, c) + a2r.Call(c, admin.AdminClient.ParseToken, o.adminClient) } func (o *Api) BlockUser(c *gin.Context) { @@ -337,43 +337,43 @@ func (o *Api) BlockUser(c *gin.Context) { } func (o *Api) UnblockUser(c *gin.Context) { - a2r.Call(admin.AdminClient.UnblockUser, o.adminClient, c) + a2r.Call(c, admin.AdminClient.UnblockUser, o.adminClient) } func (o *Api) SearchBlockUser(c *gin.Context) { - a2r.Call(admin.AdminClient.SearchBlockUser, o.adminClient, c) + a2r.Call(c, admin.AdminClient.SearchBlockUser, o.adminClient) } func (o *Api) SetClientConfig(c *gin.Context) { - a2r.Call(admin.AdminClient.SetClientConfig, o.adminClient, c) + a2r.Call(c, admin.AdminClient.SetClientConfig, o.adminClient) } func (o *Api) DelClientConfig(c *gin.Context) { - a2r.Call(admin.AdminClient.DelClientConfig, o.adminClient, c) + a2r.Call(c, admin.AdminClient.DelClientConfig, o.adminClient) } func (o *Api) GetClientConfig(c *gin.Context) { - a2r.Call(admin.AdminClient.GetClientConfig, o.adminClient, c) + a2r.Call(c, admin.AdminClient.GetClientConfig, o.adminClient) } func (o *Api) AddApplet(c *gin.Context) { - a2r.Call(admin.AdminClient.AddApplet, o.adminClient, c) + a2r.Call(c, admin.AdminClient.AddApplet, o.adminClient) } func (o *Api) DelApplet(c *gin.Context) { - a2r.Call(admin.AdminClient.DelApplet, o.adminClient, c) + a2r.Call(c, admin.AdminClient.DelApplet, o.adminClient) } func (o *Api) UpdateApplet(c *gin.Context) { - a2r.Call(admin.AdminClient.UpdateApplet, o.adminClient, c) + a2r.Call(c, admin.AdminClient.UpdateApplet, o.adminClient) } func (o *Api) SearchApplet(c *gin.Context) { - a2r.Call(admin.AdminClient.SearchApplet, o.adminClient, c) + a2r.Call(c, admin.AdminClient.SearchApplet, o.adminClient) } func (o *Api) LoginUserCount(c *gin.Context) { - a2r.Call(chat.ChatClient.UserLoginCount, o.chatClient, c) + a2r.Call(c, chat.ChatClient.UserLoginCount, o.chatClient) } func (o *Api) NewUserCount(c *gin.Context) { @@ -502,6 +502,7 @@ func (o *Api) xlsxBirth(s string) time.Time { separator = b } } + arr := strings.Split(s, string([]byte{separator})) if len(arr) != 3 { return time.Now() @@ -560,29 +561,29 @@ func (o *Api) BatchImportTemplate(c *gin.Context) { } func (o *Api) SetAllowRegister(c *gin.Context) { - a2r.Call(chat.ChatClient.SetAllowRegister, o.chatClient, c) + a2r.Call(c, chat.ChatClient.SetAllowRegister, o.chatClient) } func (o *Api) GetAllowRegister(c *gin.Context) { - a2r.Call(chat.ChatClient.GetAllowRegister, o.chatClient, c) + a2r.Call(c, chat.ChatClient.GetAllowRegister, o.chatClient) } func (o *Api) LatestApplicationVersion(c *gin.Context) { - a2r.Call(admin.AdminClient.LatestApplicationVersion, o.adminClient, c) + a2r.Call(c, admin.AdminClient.LatestApplicationVersion, o.adminClient) } func (o *Api) PageApplicationVersion(c *gin.Context) { - a2r.Call(admin.AdminClient.PageApplicationVersion, o.adminClient, c) + a2r.Call(c, admin.AdminClient.PageApplicationVersion, o.adminClient) } func (o *Api) AddApplicationVersion(c *gin.Context) { - a2r.Call(admin.AdminClient.AddApplicationVersion, o.adminClient, c) + a2r.Call(c, admin.AdminClient.AddApplicationVersion, o.adminClient) } func (o *Api) UpdateApplicationVersion(c *gin.Context) { - a2r.Call(admin.AdminClient.UpdateApplicationVersion, o.adminClient, c) + a2r.Call(c, admin.AdminClient.UpdateApplicationVersion, o.adminClient) } func (o *Api) DeleteApplicationVersion(c *gin.Context) { - a2r.Call(admin.AdminClient.DeleteApplicationVersion, o.adminClient, c) + a2r.Call(c, admin.AdminClient.DeleteApplicationVersion, o.adminClient) } diff --git a/internal/api/admin/config_manager.go b/internal/api/admin/config_manager.go index 414965d08..75f9b8df9 100644 --- a/internal/api/admin/config_manager.go +++ b/internal/api/admin/config_manager.go @@ -19,6 +19,11 @@ import ( clientv3 "go.etcd.io/etcd/client/v3" ) +const ( + // wait for Restart http call return + waitHttp = time.Millisecond * 200 +) + type ConfigManager struct { config *config.AllConfig client *clientv3.Client @@ -126,16 +131,19 @@ func compareAndSave[T any](c *gin.Context, old any, req *apistruct.SetConfigReq, } func (cm *ConfigManager) ResetConfig(c *gin.Context) { - go cm.resetConfig(c) + go func() { + if err := cm.resetConfig(c, true); err != nil { + log.ZError(c, "reset config err", err) + } + }() apiresp.GinSuccess(c, nil) } -func (cm *ConfigManager) resetConfig(c *gin.Context) { +func (cm *ConfigManager) resetConfig(c *gin.Context, checkChange bool, ops ...clientv3.Op) error { txn := cm.client.Txn(c) type initConf struct { - old any - new any - isChanged bool + old any + new any } configMap := map[string]*initConf{ config.DiscoveryConfigFileName: {old: &cm.config.Discovery, new: new(config.Discovery)}, @@ -162,13 +170,12 @@ func (cm *ConfigManager) resetConfig(c *gin.Context) { log.ZError(c, "load config failed", err) continue } - v.isChanged = reflect.DeepEqual(v.old, v.new) - if !v.isChanged { + equal := reflect.DeepEqual(v.old, v.new) + if !checkChange || !equal { changedKeys = append(changedKeys, k) } } - ops := make([]clientv3.Op, 0) for _, k := range changedKeys { data, err := json.Marshal(configMap[k].new) if err != nil { @@ -181,10 +188,10 @@ func (cm *ConfigManager) resetConfig(c *gin.Context) { txn.Then(ops...) _, err := txn.Commit() if err != nil { - log.ZError(c, "commit etcd txn failed", err) - return + return errs.WrapMsg(err, "commit etcd txn failed") } } + return nil } func (cm *ConfigManager) Restart(c *gin.Context) { @@ -193,10 +200,59 @@ func (cm *ConfigManager) Restart(c *gin.Context) { } func (cm *ConfigManager) restart(c *gin.Context) { - time.Sleep(time.Millisecond * 200) // wait for Restart http call return + time.Sleep(waitHttp) // wait for Restart http call return t := time.Now().Unix() _, err := cm.client.Put(c, etcd.BuildKey(etcd.RestartKey), strconv.Itoa(int(t))) if err != nil { log.ZError(c, "restart etcd put key failed", err) } } + +func (cm *ConfigManager) SetEnableConfigManager(c *gin.Context) { + var req apistruct.SetEnableConfigManagerReq + if err := c.BindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) + return + } + var enableStr string + if req.Enable { + enableStr = etcd.Enable + } else { + enableStr = etcd.Disable + } + resp, err := cm.client.Get(c, etcd.BuildKey(etcd.EnableConfigCenterKey)) + if err != nil { + apiresp.GinError(c, errs.WrapMsg(err, "getEnableConfigManager failed")) + return + } + if !(resp.Count > 0 && string(resp.Kvs[0].Value) == etcd.Enable) && req.Enable { + go func() { + time.Sleep(waitHttp) // wait for Restart http call return + err := cm.resetConfig(c, false, clientv3.OpPut(etcd.BuildKey(etcd.EnableConfigCenterKey), enableStr)) + if err != nil { + log.ZError(c, "writeAllConfig failed", err) + } + }() + } else { + _, err = cm.client.Put(c, etcd.BuildKey(etcd.EnableConfigCenterKey), enableStr) + if err != nil { + apiresp.GinError(c, errs.WrapMsg(err, "setEnableConfigManager failed")) + return + } + } + + apiresp.GinSuccess(c, nil) +} + +func (cm *ConfigManager) GetEnableConfigManager(c *gin.Context) { + resp, err := cm.client.Get(c, etcd.BuildKey(etcd.EnableConfigCenterKey)) + if err != nil { + apiresp.GinError(c, errs.WrapMsg(err, "getEnableConfigManager failed")) + return + } + var enable bool + if resp.Count > 0 && string(resp.Kvs[0].Value) == etcd.Enable { + enable = true + } + apiresp.GinSuccess(c, &apistruct.GetEnableConfigManagerResp{Enable: enable}) +} diff --git a/internal/api/admin/start.go b/internal/api/admin/start.go index 4740e3aa4..5ea2bdc1e 100644 --- a/internal/api/admin/start.go +++ b/internal/api/admin/start.go @@ -48,7 +48,7 @@ func Start(ctx context.Context, index int, config *Config) error { if err != nil { return err } - client, err := kdisc.NewDiscoveryRegister(&config.Discovery, config.RuntimeEnv) + client, err := kdisc.NewDiscoveryRegister(&config.Discovery, config.RuntimeEnv, nil) if err != nil { return err } @@ -209,6 +209,8 @@ func SetAdminRoute(router gin.IRouter, admin *Api, mw *chatmw.MW, cfg *Config, c configGroup.POST("/get_config", cm.GetConfig) configGroup.POST("/set_config", cm.SetConfig) configGroup.POST("/reset_config", cm.ResetConfig) + configGroup.POST("/get_enable_config_manager", cm.GetEnableConfigManager) + configGroup.POST("/set_enable_config_manager", cm.SetEnableConfigManager) } { router.POST("/restart", mw.CheckAdmin, cm.Restart) diff --git a/internal/api/chat/chat.go b/internal/api/chat/chat.go index e61978ed3..0e6254373 100644 --- a/internal/api/chat/chat.go +++ b/internal/api/chat/chat.go @@ -73,7 +73,7 @@ func (o *Api) SendVerifyCode(c *gin.Context) { } func (o *Api) VerifyCode(c *gin.Context) { - a2r.Call(chatpb.ChatClient.VerifyCode, o.chatClient, c) + a2r.Call(c, chatpb.ChatClient.VerifyCode, o.chatClient) } func (o *Api) RegisterUser(c *gin.Context) { @@ -193,7 +193,7 @@ func (o *Api) Login(c *gin.Context) { } func (o *Api) ResetPassword(c *gin.Context) { - a2r.Call(chatpb.ChatClient.ResetPassword, o.chatClient, c) + a2r.Call(c, chatpb.ChatClient.ResetPassword, o.chatClient) } func (o *Api) ChangePassword(c *gin.Context) { @@ -264,35 +264,35 @@ func (o *Api) UpdateUserInfo(c *gin.Context) { } func (o *Api) FindUserPublicInfo(c *gin.Context) { - a2r.Call(chatpb.ChatClient.FindUserPublicInfo, o.chatClient, c) + a2r.Call(c, chatpb.ChatClient.FindUserPublicInfo, o.chatClient) } func (o *Api) FindUserFullInfo(c *gin.Context) { - a2r.Call(chatpb.ChatClient.FindUserFullInfo, o.chatClient, c) + a2r.Call(c, chatpb.ChatClient.FindUserFullInfo, o.chatClient) } func (o *Api) SearchUserFullInfo(c *gin.Context) { - a2r.Call(chatpb.ChatClient.SearchUserFullInfo, o.chatClient, c) + a2r.Call(c, chatpb.ChatClient.SearchUserFullInfo, o.chatClient) } func (o *Api) SearchUserPublicInfo(c *gin.Context) { - a2r.Call(chatpb.ChatClient.SearchUserPublicInfo, o.chatClient, c) + a2r.Call(c, chatpb.ChatClient.SearchUserPublicInfo, o.chatClient) } func (o *Api) GetTokenForVideoMeeting(c *gin.Context) { - a2r.Call(chatpb.ChatClient.GetTokenForVideoMeeting, o.chatClient, c) + a2r.Call(c, chatpb.ChatClient.GetTokenForVideoMeeting, o.chatClient) } // ################## APPLET ################## func (o *Api) FindApplet(c *gin.Context) { - a2r.Call(admin.AdminClient.FindApplet, o.adminClient, c) + a2r.Call(c, admin.AdminClient.FindApplet, o.adminClient) } // ################## CONFIG ################## func (o *Api) GetClientConfig(c *gin.Context) { - a2r.Call(admin.AdminClient.GetClientConfig, o.adminClient, c) + a2r.Call(c, admin.AdminClient.GetClientConfig, o.adminClient) } // ################## CALLBACK ################## @@ -350,9 +350,9 @@ func (o *Api) SearchFriend(c *gin.Context) { } func (o *Api) LatestApplicationVersion(c *gin.Context) { - a2r.Call(admin.AdminClient.LatestApplicationVersion, o.adminClient, c) + a2r.Call(c, admin.AdminClient.LatestApplicationVersion, o.adminClient) } func (o *Api) PageApplicationVersion(c *gin.Context) { - a2r.Call(admin.AdminClient.PageApplicationVersion, o.adminClient, c) + a2r.Call(c, admin.AdminClient.PageApplicationVersion, o.adminClient) } diff --git a/internal/api/chat/start.go b/internal/api/chat/start.go index da83468ee..df14893c0 100644 --- a/internal/api/chat/start.go +++ b/internal/api/chat/start.go @@ -47,7 +47,7 @@ func Start(ctx context.Context, index int, cfg *Config) error { if err != nil { return err } - client, err := kdisc.NewDiscoveryRegister(&cfg.Discovery, cfg.RuntimeEnv) + client, err := kdisc.NewDiscoveryRegister(&cfg.Discovery, cfg.RuntimeEnv, nil) if err != nil { return err } @@ -93,6 +93,7 @@ func Start(ctx context.Context, index int, cfg *Config) error { config.ChatAPIChatCfgFileName, config.DiscoveryConfigFileName, config.ShareFileName, + config.LogConfigFileName, }, ) cm.Watch(ctx) diff --git a/pkg/common/apistruct/config_manager.go b/pkg/common/apistruct/config_manager.go index 84b8fb36b..9b8641c9d 100644 --- a/pkg/common/apistruct/config_manager.go +++ b/pkg/common/apistruct/config_manager.go @@ -14,3 +14,11 @@ type SetConfigReq struct { ConfigName string `json:"configName"` Data string `json:"data"` } + +type SetEnableConfigManagerReq struct { + Enable bool `json:"enable"` +} + +type GetEnableConfigManagerResp struct { + Enable bool `json:"enable"` +} diff --git a/pkg/common/cmd/admin_rpc.go b/pkg/common/cmd/admin_rpc.go index e46c929a3..508b165a6 100644 --- a/pkg/common/cmd/admin_rpc.go +++ b/pkg/common/cmd/admin_rpc.go @@ -62,6 +62,7 @@ func (a *AdminRpcCmd) runE() error { config.DiscoveryConfigFileName, config.MongodbConfigFileName, config.ShareFileName, - }, + config.LogConfigFileName, + }, nil, admin.Start) } diff --git a/pkg/common/cmd/chat_rpc.go b/pkg/common/cmd/chat_rpc.go index 7f4bd859b..5f82b09e2 100644 --- a/pkg/common/cmd/chat_rpc.go +++ b/pkg/common/cmd/chat_rpc.go @@ -62,6 +62,7 @@ func (a *ChatRpcCmd) runE() error { config.DiscoveryConfigFileName, config.MongodbConfigFileName, config.ShareFileName, - }, + config.LogConfigFileName, + }, nil, chat.Start) } diff --git a/pkg/common/cmd/root.go b/pkg/common/cmd/root.go index 6521e551b..291ebde8e 100644 --- a/pkg/common/cmd/root.go +++ b/pkg/common/cmd/root.go @@ -99,7 +99,7 @@ func (r *RootCmd) initEtcd() error { return err } if disConfig.Enable == kdisc.ETCDCONST { - discov, _ := kdisc.NewDiscoveryRegister(&disConfig, env) + discov, _ := kdisc.NewDiscoveryRegister(&disConfig, env, nil) r.etcdClient = discov.(*etcd.SvcDiscoveryRegistryImpl).GetClient() } return nil @@ -119,6 +119,9 @@ func (r *RootCmd) persistentPreRun(cmd *cobra.Command, opts ...func(*CmdOpts)) e if err := r.initializeLogger(cmdOpts); err != nil { return errs.WrapMsg(err, "failed to initialize logger") } + if err := r.etcdClient.Close(); err != nil { + return errs.WrapMsg(err, "failed to close etcd client") + } return nil } @@ -150,9 +153,24 @@ func (r *RootCmd) updateConfigFromEtcd(opts *CmdOpts) error { if r.etcdClient == nil { return nil } + ctx := context.TODO() + + res, err := r.etcdClient.Get(ctx, disetcd.BuildKey(disetcd.EnableConfigCenterKey)) + if err != nil { + log.ZWarn(ctx, "root cmd updateConfigFromEtcd, etcd Get EnableConfigCenterKey err: %v", errs.Wrap(err)) + return nil + } + if res.Count == 0 { + return nil + } else { + if string(res.Kvs[0].Value) == disetcd.Disable { + return nil + } else if string(res.Kvs[0].Value) != disetcd.Enable { + return errs.New("unknown EnableConfigCenter value").Wrap() + } + } update := func(configFileName string, configStruct any) error { - ctx := context.TODO() key := disetcd.BuildKey(configFileName) etcdRes, err := r.etcdClient.Get(ctx, key) if err != nil { diff --git a/pkg/common/kdisc/discoveryregister.go b/pkg/common/kdisc/discoveryregister.go index 95d7672b8..efb6d6db0 100644 --- a/pkg/common/kdisc/discoveryregister.go +++ b/pkg/common/kdisc/discoveryregister.go @@ -31,7 +31,7 @@ const ( ) // NewDiscoveryRegister creates a new service discovery and registry client based on the provided environment type. -func NewDiscoveryRegister(discovery *config.Discovery, runtimeEnv string) (discovery.SvcDiscoveryRegistry, error) { +func NewDiscoveryRegister(discovery *config.Discovery, runtimeEnv string, watchNames []string) (discovery.SvcDiscoveryRegistry, error) { if runtimeEnv == KUBERNETESCONST { return kubernetes.NewKubernetesConnManager(discovery.Kubernetes.Namespace) } @@ -41,6 +41,7 @@ func NewDiscoveryRegister(discovery *config.Discovery, runtimeEnv string) (disco return etcd.NewSvcDiscoveryRegistry( discovery.Etcd.RootDirectory, discovery.Etcd.Address, + watchNames, etcd.WithDialTimeout(10*time.Second), etcd.WithMaxCallSendMsgSize(20*1024*1024), etcd.WithUsernameAndPassword(discovery.Etcd.Username, discovery.Etcd.Password)) diff --git a/pkg/common/kdisc/etcd/config_manager.go b/pkg/common/kdisc/etcd/config_manager.go index 4e4e065b8..70d37c323 100644 --- a/pkg/common/kdisc/etcd/config_manager.go +++ b/pkg/common/kdisc/etcd/config_manager.go @@ -14,11 +14,6 @@ import ( clientv3 "go.etcd.io/etcd/client/v3" ) -const ( - ConfigKeyPrefix = "/chat/config/" - RestartKey = "restart" -) - var ( ShutDowns []func() error ) diff --git a/pkg/common/kdisc/etcd/const.go b/pkg/common/kdisc/etcd/const.go new file mode 100644 index 000000000..bae8be996 --- /dev/null +++ b/pkg/common/kdisc/etcd/const.go @@ -0,0 +1,9 @@ +package etcd + +const ( + ConfigKeyPrefix = "/chat/config/" + RestartKey = "restart" + EnableConfigCenterKey = "enable-config-center" + Enable = "enable" + Disable = "disable" +) diff --git a/pkg/common/startrpc/start.go b/pkg/common/startrpc/start.go index e8b98a423..a2d1cbd1f 100644 --- a/pkg/common/startrpc/start.go +++ b/pkg/common/startrpc/start.go @@ -31,7 +31,7 @@ import ( // Start rpc server. func Start[T any](ctx context.Context, discovery *config.Discovery, listenIP, registerIP string, rpcPorts []int, index int, rpcRegisterName string, share *config.Share, config T, - watchConfigNames []string, + watchConfigNames []string, watchServiceNames []string, rpcFn func(ctx context.Context, config T, client discovery.SvcDiscoveryRegistry, server *grpc.Server) error, options ...grpc.ServerOption) error { runtimeEnv := runtimeenv.PrintRuntimeEnvironment() @@ -51,7 +51,7 @@ func Start[T any](ctx context.Context, discovery *config.Discovery, listenIP, } defer listener.Close() - client, err := kdisc.NewDiscoveryRegister(discovery, runtimeEnv) + client, err := kdisc.NewDiscoveryRegister(discovery, runtimeEnv, watchServiceNames) if err != nil { return err } From 9dbe602188c31539a81686346125fb72a4e962cb Mon Sep 17 00:00:00 2001 From: icey-yu <119291641+icey-yu@users.noreply.github.com> Date: Wed, 8 Jan 2025 10:56:29 +0800 Subject: [PATCH 24/36] fix: err (#623) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 74f4f05ff..2056f0067 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/mitchellh/mapstructure v1.5.0 github.com/openimsdk/gomake v0.0.14-alpha.5 github.com/openimsdk/protocol v0.0.72 - github.com/openimsdk/tools v0.0.50-alpha.64 + github.com/openimsdk/tools v0.0.50-alpha.65 github.com/redis/go-redis/v9 v9.5.1 github.com/spf13/cobra v1.8.0 github.com/spf13/viper v1.18.2 diff --git a/go.sum b/go.sum index 76b85930f..76ba8f3a9 100644 --- a/go.sum +++ b/go.sum @@ -217,8 +217,8 @@ github.com/openimsdk/gomake v0.0.14-alpha.5 h1:VY9c5x515lTfmdhhPjMvR3BBRrRquAUCF github.com/openimsdk/gomake v0.0.14-alpha.5/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI= github.com/openimsdk/protocol v0.0.72 h1:K+vslwaR7lDXyBzb07UuEQITaqsgighz7NyXVIWsu6A= github.com/openimsdk/protocol v0.0.72/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8= -github.com/openimsdk/tools v0.0.50-alpha.64 h1:KmtE8V2K8atQJJg1xq2ySSrPQyf8ldwk8fw6jRnsxCw= -github.com/openimsdk/tools v0.0.50-alpha.64/go.mod h1:B+oqV0zdewN7OiEHYJm+hW+8/Te7B8tHHgD8rK5ZLZk= +github.com/openimsdk/tools v0.0.50-alpha.65 h1:BRtxkyWxDWPHuHphSwEyHZj7kJSR98am/fHOH84naK8= +github.com/openimsdk/tools v0.0.50-alpha.65/go.mod h1:B+oqV0zdewN7OiEHYJm+hW+8/Te7B8tHHgD8rK5ZLZk= github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pion/datachannel v1.5.5 h1:10ef4kwdjije+M9d7Xm9im2Y3O6A6ccQb0zcqZcJew8= From 7e66149fbe2fb5de95a638d41aede870c2a0e67e Mon Sep 17 00:00:00 2001 From: Monet Lee Date: Thu, 23 Jan 2025 15:38:56 +0800 Subject: [PATCH 25/36] build: improve workflows and docker contents. (#629) --- .github/workflows/build-docker-image.yml | 161 ++++++---------- .github/workflows/changelog.yml | 78 ++++++++ .github/workflows/chat-build-test.yml | 157 +++++++++++++++ .github/workflows/chatci.yml | 108 ----------- ...cker-build-and-release-services-images.yml | 12 +- .github/workflows/merge-from-milestone.yml | 178 ++++++------------ Dockerfile | 11 +- 7 files changed, 359 insertions(+), 346 deletions(-) create mode 100644 .github/workflows/changelog.yml create mode 100644 .github/workflows/chat-build-test.yml delete mode 100644 .github/workflows/chatci.yml diff --git a/.github/workflows/build-docker-image.yml b/.github/workflows/build-docker-image.yml index 64d5d0c5c..56f9f547e 100644 --- a/.github/workflows/build-docker-image.yml +++ b/.github/workflows/build-docker-image.yml @@ -3,143 +3,100 @@ name: Publish Docker image on: push: branches: - - main + # - main - release-* - tags: - - v* + # tags: + # - v* + release: + types: [published] + workflow_dispatch: + inputs: + tag: + description: "Tag version to be used for Docker image" + required: true + default: "v3.8.0" env: - # Common versions - GO_VERSION: "1.20" + GO_VERSION: "1.22" jobs: - build-dockerhub: + build-image: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: actions/checkout@v4 -# docker.io/openim/openim-chat:latest - - name: Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@v4.6.0 - with: - images: openim/openim-chat - # generate Docker tags based on the following events/attributes - tags: | - type=ref,event=tag - type=schedule - type=ref,event=branch - type=ref,event=pr - type=semver,pattern={{version}} - type=semver,pattern=v{{version}} - type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{major}} - type=sha + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3.8.0 - name: Log in to Docker Hub - uses: docker/login-action@v2 + uses: docker/login-action@v3.3.0 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - - name: Build and push Docker image - uses: docker/build-push-action@v4 - with: - context: . - # linux/ppc64le,linux/s390x - platforms: linux/amd64,linux/arm64 - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - - build-aliyun: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 -# registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-chat:latest - - name: Extract metadata (tags, labels) for Docker - id: meta2 - uses: docker/metadata-action@v4.6.0 + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3.3.0 with: - images: registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-chat - tags: | - type=ref,event=tag - type=schedule - type=ref,event=branch - type=ref,event=pr - type=semver,pattern={{version}} - type=semver,pattern=v{{version}} - type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{major}} - type=sha + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} - - name: Log in to AliYun Docker Hub - uses: docker/login-action@v2 + - name: Log in to Aliyun Container Registry + uses: docker/login-action@v3.3.0 with: registry: registry.cn-hangzhou.aliyuncs.com username: ${{ secrets.ALIREGISTRY_USERNAME }} password: ${{ secrets.ALIREGISTRY_TOKEN }} - - - name: Build and push Docker image - uses: docker/build-push-action@v4 - with: - context: . - # linux/ppc64le,linux/s390x - platforms: linux/amd64,linux/arm64 - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta2.outputs.tags }} - labels: ${{ steps.meta2.outputs.labels }} - build-ghcr: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 -# ghcr.io/openimsdk/openim-chat:latest - name: Extract metadata (tags, labels) for Docker - id: meta3 - uses: docker/metadata-action@v4.6.0 + id: meta + uses: docker/metadata-action@v5.6.0 with: - images: ghcr.io/openimsdk/openim-chat + images: | + openim/openim-chat + ghcr.io/openimsdk/openim-chat + registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-chat tags: | type=ref,event=tag type=schedule type=ref,event=branch - type=ref,event=pr - type=semver,pattern={{version}} + # type=ref,event=pr + # type=semver,pattern={{version}} type=semver,pattern=v{{version}} - type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{major}} + type=semver,pattern=release-{{raw}} type=sha - - - name: Log in to GitHub Container Registry - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} + type=raw,value=${{ github.event.inputs.tag }} - name: Build and push Docker image uses: docker/build-push-action@v4 with: context: . - # linux/ppc64le,linux/s390x platforms: linux/amd64,linux/arm64 push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta3.outputs.tags }} - labels: ${{ steps.meta3.outputs.labels }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Verify multi-platform support + run: | + images=("openim/openim-chat" "ghcr.io/openimsdk/openim-chat" "registry.cn-hangzhou.aliyuncs.com/openimsdk/openim-chat") + for image in "${images[@]}"; do + for tag in $(echo "${{ steps.meta.outputs.tags }}" | tr ',' '\n'); do + manifest=$(docker manifest inspect "$image:$tag" || echo "error") + if [[ "$manifest" == "error" ]]; then + echo "Manifest not found for $image:$tag" + exit 1 + fi + amd64_found=$(echo "$manifest" | jq '.manifests[] | select(.platform.architecture == "amd64")') + arm64_found=$(echo "$manifest" | jq '.manifests[] | select(.platform.architecture == "arm64")') + if [[ -z "$amd64_found" ]]; then + echo "Multi-platform support check failed for $image:$tag - missing amd64" + exit 1 + fi + if [[ -z "$arm64_found" ]]; then + echo "Multi-platform support check failed for $image:$tag - missing arm64" + exit 1 + fi + done + done diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml new file mode 100644 index 000000000..12845328f --- /dev/null +++ b/.github/workflows/changelog.yml @@ -0,0 +1,78 @@ +name: Release Changelog + +on: + release: + types: [released] + +permissions: + contents: write + pull-requests: write + +jobs: + update-changelog: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Run Go Changelog Generator + run: | + # Run the Go changelog generator, passing the release tag if available + if [ "${{ github.event.release.tag_name }}" = "latest" ]; then + go run tools/changelog/changelog.go > "${{ github.event.release.tag_name }}-changelog.md" + else + go run tools/changelog/changelog.go "${{ github.event.release.tag_name }}" > "${{ github.event.release.tag_name }}-changelog.md" + fi + + - name: Handle changelog files + run: | + # Ensure that the CHANGELOG directory exists + mkdir -p CHANGELOG + + # Extract Major.Minor version by removing the 'v' prefix from the tag name + TAG_NAME=${{ github.event.release.tag_name }} + CHANGELOG_VERSION_NUMBER=$(echo "$TAG_NAME" | sed 's/^v//' | grep -oP '^\d+\.\d+') + + # Define the new changelog file path + CHANGELOG_FILENAME="CHANGELOG-$CHANGELOG_VERSION_NUMBER.md" + CHANGELOG_PATH="CHANGELOG/$CHANGELOG_FILENAME" + + # Check if the changelog file for the current release already exists + if [ -f "$CHANGELOG_PATH" ]; then + # If the file exists, append the new changelog to the existing one + cat "$CHANGELOG_PATH" >> "${TAG_NAME}-changelog.md" + # Overwrite the existing changelog with the updated content + mv "${TAG_NAME}-changelog.md" "$CHANGELOG_PATH" + else + # If the changelog file doesn't exist, rename the temp changelog file to the new changelog file + mv "${TAG_NAME}-changelog.md" "$CHANGELOG_PATH" + + # Ensure that README.md exists + if [ ! -f "CHANGELOG/README.md" ]; then + echo -e "# CHANGELOGs\n\n" > CHANGELOG/README.md + fi + + # Add the new changelog entry at the top of the README.md + if ! grep -q "\[$CHANGELOG_FILENAME\]" CHANGELOG/README.md; then + sed -i "3i- [$CHANGELOG_FILENAME](./$CHANGELOG_FILENAME)" CHANGELOG/README.md + # Remove the extra newline character added by sed + # sed -i '4d' CHANGELOG/README.md + fi + fi + + - name: Clean up + run: | + # Remove any temporary files that were created during the process + rm -f "${{ github.event.release.tag_name }}-changelog.md" + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7.0.5 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: "Update CHANGELOG for release ${{ github.event.release.tag_name }}" + title: "Update CHANGELOG for release ${{ github.event.release.tag_name }}" + body: "This PR updates the CHANGELOG files for release ${{ github.event.release.tag_name }}" + branch: changelog-${{ github.event.release.tag_name }} + base: main + delete-branch: true + labels: changelog diff --git a/.github/workflows/chat-build-test.yml b/.github/workflows/chat-build-test.yml new file mode 100644 index 000000000..c762332ad --- /dev/null +++ b/.github/workflows/chat-build-test.yml @@ -0,0 +1,157 @@ +name: OpenIM Chat Build Test + +on: + push: + branches: + - main + - release-* + paths-ignore: + - "docs/**" + - "README.md" + - "README_zh-CN.md" + - "**.md" + - "docs/**" + - "CONTRIBUTING.md" + pull_request: + branches: + - main + - release-* + paths-ignore: + - "README.md" + - "README_zh-CN.md" + - "CONTRIBUTING/**" + - "**.md" + - "docs/**" + workflow_dispatch: + +jobs: + build-linux: + name: Execute OpenIM Script On Linux + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + # environment: + # name: openim + strategy: + matrix: + arch: [amd64] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: "1.22" + + - name: init + run: sudo bash bootstrap.sh + timeout-minutes: 20 + + - name: Checkout chat repository + uses: actions/checkout@v4 + with: + repository: "openimsdk/open-im-server" + path: "server-repo" + + - name: Set up Docker for Linux + run: | + cd ${{ github.workspace }}/server-repo + sudo docker compose up -d + sudo sleep 30 # Increased sleep time for better stability + timeout-minutes: 30 # Increased timeout for Docker setup + + - name: Build and Start IM Serevr Services + run: | + cd ${{ github.workspace }}/server-repo + sudo mage + sudo mage start + sudo mage check + + - name: Build, Start, Check Services and Print Logs for Linux + run: | + sudo mage + sudo mage start + sudo mage check + + - name: Restart Services and Print Logs + run: | + sudo mage stop + sudo mage start + sudo mage check + + - name: Test Chat + run: | + check_error() { + echo "Response: $1" + errCode=$(echo $1 | jq -r '.errCode') + if [ "$errCode" != "0" ]; then + errMsg=$(echo $1 | jq -r '.errMsg') + echo "Error: $errMsg" + exit 1 + fi + } + + # Test register + response1=$(curl -X POST -H "Content-Type: application/json" -H "operationID: imAdmin" -d '{ + "verifyCode": "666666", + "platform": 3, + "autoLogin": true, + "user":{ + "nickname": "test12312", + "areaCode":"+86", + "phoneNumber": "12345678190", + "password":"test123456" + } + }' http://127.0.0.1:10008/account/register) + check_error "$response1" + userID1=$(echo $response1 | jq -r '.data.userID') + echo "userID1: $userID1" + + response2=$(curl -X POST -H "Content-Type: application/json" -H "operationID: imAdmin" -d '{ + "verifyCode": "666666", + "platform": 3, + "autoLogin": true, + "user":{ + "nickname": "test22312", + "areaCode":"+86", + "phoneNumber": "12345678290", + "password":"test123456" + } + }' http://127.0.0.1:10008/account/register) + check_error "$response2" + userID2=$(echo $response2 | jq -r '.data.userID') + echo "userID2: $userID2" + + # Test login + login_response=$(curl -X POST -H "Content-Type: application/json" -H "operationID: imAdmin" -d '{ + "platform": 3, + "areaCode":"+86", + "phoneNumber": "12345678190", + "password":"test123456" + }' http://localhost:10008/account/login) + check_error "$login_response" + + # Test get admin token + get_admin_token_response=$(curl -X POST -H "Content-Type: application/json" -H "operationID: imAdmin" -d '{ + "secret": "openIM123", + "platformID": 2, + "userID": "imAdmin" + }' http://127.0.0.1:10002/auth/get_admin_token) + check_error "$get_admin_token_response" + adminToken=$(echo $get_admin_token_response | jq -r '.data.token') + echo "adminToken: $adminToken" + + # Test send message + send_msg_response=$(curl -X POST -H "Content-Type: application/json" -H "operationID: imAdmin" -H "token: $adminToken" -d '{ + "sendID": "'$userID1'", + "recvID": "'$userID2'", + "senderPlatformID": 3, + "content": { + "content": "hello!!" + }, + "contentType": 101, + "sessionType": 1 + }' http://127.0.0.1:10002/msg/send_msg) + check_error "$send_msg_response" diff --git a/.github/workflows/chatci.yml b/.github/workflows/chatci.yml deleted file mode 100644 index e6c1b7a83..000000000 --- a/.github/workflows/chatci.yml +++ /dev/null @@ -1,108 +0,0 @@ -name: OpenIM CI Auto Build - -on: - push: - branches: - - main - - release-* - paths-ignore: - - "docs/**" - - "README.md" - - "README_zh-CN.md" - - "**.md" - - "docs/**" - - "CONTRIBUTING.md" - pull_request: - branches: - - main - - release-* - paths-ignore: - - "README.md" - - "README_zh-CN.md" - - "CONTRIBUTING/**" - - "**.md" - - "docs/**" - workflow_dispatch: - -jobs: - - build-linux: - name: Execute OpenIM Script On Linux - runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write - # environment: - # name: openim - strategy: - matrix: - arch: [amd64] - - steps: - - uses: actions/checkout@v3 - - - name: Set up Go - uses: actions/setup-go@v4 - with: - go-version: '1.21' - - - name: init - run: sudo bash bootstrap.sh - timeout-minutes: 20 - - - name: Checkout chat repository - uses: actions/checkout@v4 - with: - repository: 'openimsdk/open-im-server' - path: 'server-repo' - - - name: Set up Docker for Linux - run: | - cd ${{ github.workspace }}/server-repo - sudo docker compose up -d - sudo sleep 30 # Increased sleep time for better stability - timeout-minutes: 20 # Increased timeout for Docker setup - - - name: Build and Start IM Serevr Services - run: | - cd ${{ github.workspace }}/server-repo - sudo mage - sudo mage start - sudo mage check - - - name: Build, Start, Check Services and Print Logs for Linux - run: | - sudo mage - sudo mage start - sudo mage check - - - - name: Restart Services and Print Logs - run: | - sudo mage stop - sudo mage start - sudo mage check - - - - # - name: Checkout e2e repository - # uses: actions/checkout@v4 - # with: - # repository: "openimsdk/test-e2e" - # path: e2e-repo - - # - name: Set up Python 3.9 - # uses: actions/setup-python@v4 - # with: - # python-version: '3.9' - - # - name: Install dependencies - # run: | - # cd ${{ github.workspace }}/e2e-repo - # pip install PyYAML webdriver_manager selenium pytest - - # - name: Run tests - # run: | - # cd ${{ github.workspace }}/e2e-repo - # pytest main.py - \ No newline at end of file diff --git a/.github/workflows/docker-build-and-release-services-images.yml b/.github/workflows/docker-build-and-release-services-images.yml index ed4c7ad38..bfb018ea4 100644 --- a/.github/workflows/docker-build-and-release-services-images.yml +++ b/.github/workflows/docker-build-and-release-services-images.yml @@ -19,26 +19,26 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3.8.0 - name: Log in to Docker Hub - uses: docker/login-action@v2 + uses: docker/login-action@v3.3.0 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Log in to GitHub Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v3.3.0 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Log in to Aliyun Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v3.3.0 with: registry: registry.cn-hangzhou.aliyuncs.com username: ${{ secrets.ALIREGISTRY_USERNAME }} @@ -52,9 +52,7 @@ jobs: type=ref,event=tag type=schedule type=ref,event=branch - type=semver,pattern={{version}} type=semver,pattern=v{{version}} - # type=semver,pattern={{major}}.{{minor}} type=semver,pattern=release-{{raw}} type=sha type=raw,value=${{ github.event.inputs.tag }} diff --git a/.github/workflows/merge-from-milestone.yml b/.github/workflows/merge-from-milestone.yml index 939c08fcb..2c875f252 100644 --- a/.github/workflows/merge-from-milestone.yml +++ b/.github/workflows/merge-from-milestone.yml @@ -1,4 +1,4 @@ -name: Create Pre-Release PR from Milestone +name: Create Individual PRs from Milestone permissions: contents: write @@ -9,24 +9,24 @@ on: workflow_dispatch: inputs: milestone_name: - description: 'Milestone name to collect closed PRs from' + description: "Milestone name to collect closed PRs from" required: true - default: 'v1.8.3' + default: "v1.8.5" target_branch: - description: 'Target branch to merge the consolidated PR' + description: "Target branch to merge the consolidated PR" required: true - default: 'pre-release-v1.8.3' + default: "pre-release-v1.8.5" env: - MILESTONE_NAME: ${{ github.event.inputs.milestone_name || 'v1.8.3' }} - TARGET_BRANCH: ${{ github.event.inputs.target_branch || 'pre-release-v1.8.3' }} + MILESTONE_NAME: ${{ github.event.inputs.milestone_name || 'v1.8.5' }} + TARGET_BRANCH: ${{ github.event.inputs.target_branch || 'pre-release-v1.8.5' }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} BOT_TOKEN: ${{ secrets.BOT_TOKEN }} LABEL_NAME: cherry-picked - TEMP_DIR: /tmp # Using /tmp as the temporary directory + TEMP_DIR: /tmp jobs: - cherry_pick_milestone_prs: + merge_milestone_prs: runs-on: ubuntu-latest steps: - name: Setup temp directory @@ -47,7 +47,6 @@ jobs: - name: Setup Git User for OpenIM-Robot run: | - # Set up Git credentials for the bot git config --global user.email "OpenIM-Robot@users.noreply.github.com" git config --global user.name "OpenIM-Robot" @@ -83,136 +82,65 @@ jobs: if ! echo "$labels" | grep -q "${LABEL_NAME}"; then echo "PR #$pr_number does not have the 'cherry-picked' label. Adding to the list." echo "$pr_number" >> ${{ env.TEMP_DIR }}/pr_numbers.txt - else - echo "PR #$pr_number already has the 'cherry-picked' label. Skipping." fi done - # Sort the filtered PR numbers sort -n ${{ env.TEMP_DIR }}/pr_numbers.txt -o ${{ env.TEMP_DIR }}/pr_numbers.txt - echo "Filtered and sorted PR numbers:" - cat ${{ env.TEMP_DIR }}/pr_numbers.txt || echo "No closed PR numbers found for milestone." - - - name: Fetch Merge Commits for PRs and Generate Title and Body + - name: Create Individual PRs run: | - # Ensure the files are initialized - > ${{ env.TEMP_DIR }}/commit_hashes.txt - > ${{ env.TEMP_DIR }}/pr_title.txt - > ${{ env.TEMP_DIR }}/pr_body.txt - - # Write description to the PR body - echo "### Description:" >> ${{ env.TEMP_DIR }}/pr_body.txt - echo "Merging PRs from milestone \`$MILESTONE_NAME\` into target branch \`$TARGET_BRANCH\`." >> ${{ env.TEMP_DIR }}/pr_body.txt - echo "" >> ${{ env.TEMP_DIR }}/pr_body.txt - echo "### Need Merge PRs:" >> ${{ env.TEMP_DIR }}/pr_body.txt - - pr_numbers_in_title="" - - # Process sorted PR numbers and generate commit hashes for pr_number in $(cat ${{ env.TEMP_DIR }}/pr_numbers.txt); do - echo "Processing PR #$pr_number" pr_details=$(curl -s -H "Authorization: token $BOT_TOKEN" \ -H "Accept: application/vnd.github+json" \ "https://api.github.com/repos/${{ github.repository }}/pulls/$pr_number") pr_title=$(echo "$pr_details" | jq -r '.title') + pr_body=$(echo "$pr_details" | jq -r '.body') + pr_creator=$(echo "$pr_details" | jq -r '.user.login') merge_commit=$(echo "$pr_details" | jq -r '.merge_commit_sha') short_commit_hash=$(echo "$merge_commit" | cut -c 1-7) - # Append PR details to the body - echo "- $pr_title: (#$pr_number) ($short_commit_hash)" >> ${{ env.TEMP_DIR }}/pr_body.txt - - if [ "$merge_commit" != "null" ];then - echo "$merge_commit" >> ${{ env.TEMP_DIR }}/commit_hashes.txt - echo "#$pr_number" >> ${{ env.TEMP_DIR }}/pr_title.txt - pr_numbers_in_title="$pr_numbers_in_title #$pr_number" - fi - done + if [ "$merge_commit" != "null" ]; then + git fetch origin + + echo "Checking out target branch: $TARGET_BRANCH" + git checkout $TARGET_BRANCH + + echo "Pulling latest changes from target branch: $TARGET_BRANCH" + git pull origin $TARGET_BRANCH + + cherry_pick_branch="cherry-pick-${short_commit_hash}" + git checkout -b $cherry_pick_branch + + echo "Cherry-picking commit: $merge_commit" + if ! git cherry-pick "$merge_commit" --strategy=recursive -X theirs; then + echo "Cherry-pick encountered conflicts, attempting to continue..." + git cherry-pick --continue || { echo "Cherry-pick failed"; exit 1; } + fi + + git remote set-url origin "https://${BOT_TOKEN}@github.com/${{ github.repository }}.git" + + echo "Pushing branch: $cherry_pick_branch" + git push origin $cherry_pick_branch --force || { echo "Push failed"; exit 1; } + + new_pr_title="$pr_title [Created by @$pr_creator from #$pr_number]" + new_pr_body="$pr_body + > This PR is created from original PR #$pr_number." + + response=$(curl -s -X POST -H "Authorization: token $BOT_TOKEN" \ + -H "Accept: application/vnd.github+json" \ + https://api.github.com/repos/${{ github.repository }}/pulls \ + -d "$(jq -n --arg title "$new_pr_title" \ + --arg head "$cherry_pick_branch" \ + --arg base "$TARGET_BRANCH" \ + --arg body "$new_pr_body" \ + '{title: $title, head: $head, base: $base, body: $body}')") - commit_hashes=$(cat ${{ env.TEMP_DIR }}/commit_hashes.txt | tr '\n' ' ') - first_commit_hash=$(head -n 1 ${{ env.TEMP_DIR }}/commit_hashes.txt) - cherry_pick_branch="cherry-pick-${first_commit_hash:0:7}" - echo "COMMIT_HASHES=$commit_hashes" >> $GITHUB_ENV - echo "CHERRY_PICK_BRANCH=$cherry_pick_branch" >> $GITHUB_ENV - echo "pr_numbers_in_title=$pr_numbers_in_title" >> $GITHUB_ENV + new_pr_number=$(echo "$response" | jq -r '.number') + echo "Created PR #$new_pr_number" - - name: Pull and Cherry-pick Commits, Then Push - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - BOT_TOKEN: ${{ secrets.BOT_TOKEN }} - run: | - # Fetch and pull the latest changes from the target branch - git fetch origin - git checkout $TARGET_BRANCH - git pull origin $TARGET_BRANCH - - # Create a new branch for cherry-picking - git checkout -b $CHERRY_PICK_BRANCH - - # Cherry-pick the commits and handle conflicts - for commit_hash in $COMMIT_HASHES; do - echo "Attempting to cherry-pick commit $commit_hash" - if ! git cherry-pick "$commit_hash" --strategy=recursive -X theirs; then - echo "Conflict detected for $commit_hash. Resolving with incoming changes." - conflict_files=$(git diff --name-only --diff-filter=U) - echo "Conflicting files:" - echo "$conflict_files" - - for file in $conflict_files; do - if [ -f "$file" ]; then - echo "Resolving conflict for $file" - git add "$file" - else - echo "File $file has been deleted. Skipping." - git rm "$file" - fi - done - - echo "Conflicts resolved. Continuing cherry-pick." - git cherry-pick --continue - else - echo "Cherry-pick successful for commit $commit_hash." + curl -s -X POST -H "Authorization: token $GITHUB_TOKEN" \ + -H "Accept: application/vnd.github+json" \ + -d '{"labels": ["milestone-merge"]}' \ + "https://api.github.com/repos/${{ github.repository }}/issues/$new_pr_number/labels" fi done - - # Push the cherry-pick branch to the repository - git remote set-url origin "https://${BOT_TOKEN}@github.com/${{ github.repository }}.git" - git push origin $CHERRY_PICK_BRANCH --force - - - name: Create Pull Request - run: | - # Prepare and create the PR - pr_title="deps: Merge ${{ env.pr_numbers_in_title }} PRs into $TARGET_BRANCH" - pr_body=$(cat ${{ env.TEMP_DIR }}/pr_body.txt) - - echo "Prepared PR title:" - echo "$pr_title" - echo "Prepared PR body:" - echo "$pr_body" - - # Create the PR using the GitHub API - response=$(curl -s -X POST -H "Authorization: token $BOT_TOKEN" \ - -H "Accept: application/vnd.github+json" \ - https://api.github.com/repos/${{ github.repository }}/pulls \ - -d "$(jq -n --arg title "$pr_title" \ - --arg head "$CHERRY_PICK_BRANCH" \ - --arg base "$TARGET_BRANCH" \ - --arg body "$pr_body" \ - '{title: $title, head: $head, base: $base, body: $body}')") - - pr_number=$(echo "$response" | jq -r '.number') - echo "$pr_number" > ${{ env.TEMP_DIR }}/created_pr_number.txt - echo "Created PR #$pr_number" - - - name: Add Label to Created Pull Request - run: | - # Add 'milestone-merge' label to the created PR - pr_number=$(cat ${{ env.TEMP_DIR }}/created_pr_number.txt) - echo "Adding label to PR #$pr_number" - - curl -s -X POST -H "Authorization: token $GITHUB_TOKEN" \ - -H "Accept: application/vnd.github+json" \ - -d '{"labels": ["milestone-merge"]}' \ - "https://api.github.com/repos/${{ github.repository }}/issues/$pr_number/labels" - - echo "Added 'milestone-merge' label to PR #$pr_number." diff --git a/Dockerfile b/Dockerfile index 8751beace..faff0a0ea 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Use Go 1.21 Alpine as the base image for building the application -FROM golang:1.22-alpine as builder +FROM golang:1.22-alpine AS builder # Define the base directory for the application as an environment variable ENV SERVER_DIR=/openim-chat @@ -8,12 +8,15 @@ ENV SERVER_DIR=/openim-chat WORKDIR $SERVER_DIR # Set the Go proxy to improve dependency resolution speed -ENV GOPROXY=https://goproxy.io,direct +# ENV GOPROXY=https://goproxy.io,direct + +COPY go.mod go.sum ./ + +RUN go mod download # Copy all files from the current directory into the container COPY . . -RUN go mod download # Install Mage to use for building the application RUN go install github.com/magefile/mage@v1.15.0 @@ -46,4 +49,4 @@ COPY --from=builder $SERVER_DIR/go.sum $SERVER_DIR/ RUN go get github.com/openimsdk/gomake@v0.0.14-alpha.5 # Set the command to run when the container starts -ENTRYPOINT ["sh", "-c", "mage start && tail -f /dev/null"] +ENTRYPOINT ["sh", "-c", "mage start && tail -f /dev/null"] \ No newline at end of file From e8ed4726debffe348d20f6cc1b272df24ced9886 Mon Sep 17 00:00:00 2001 From: skiffer-git <72860476+skiffer-git@users.noreply.github.com> Date: Tue, 22 Apr 2025 21:56:04 +0800 Subject: [PATCH 26/36] Update README.md --- README.md | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/README.md b/README.md index 9e466965c..a8c1e1815 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,5 @@ # openim-chat -## 📄 License Options for OpenIM Source Code - -You may use the OpenIM source code to create compiled versions not originally produced by OpenIM under one of the following two licensing options: - -### 1. GNU General Public License v3.0 (GPLv3) 🆓 - -+ This option is governed by the Free Software Foundation's [GPL v3.0](https://www.gnu.org/licenses/gpl-3.0.en.html). -+ Usage is subject to certain exceptions as outlined in this policy. - -### 2. Commercial License 💼 - -+ Obtain a commercial license by contacting OpenIM. -+ For more details and licensing inquiries, please email 📧 [contact@openim.io](mailto:contact@openim.io). ## 🧩 Feature Overview @@ -98,4 +85,4 @@ mage stop ## 🚨 License -:scroll: chat is licensed under the [GPL-3.0 license](https://github.com/openimsdk/chat#GPL-3.0-1-ov-file). See the [LICENSE](https://github.com/openimsdk/chat/tree/main/LICENSE) for the full license text. +This software is licensed under the Apache License 2.0 From 3925cbb1f90a161b591e04702cc6628d315c5d77 Mon Sep 17 00:00:00 2001 From: icey-yu <119291641+icey-yu@users.noreply.github.com> Date: Thu, 6 Mar 2025 16:43:02 +0800 Subject: [PATCH 27/36] feat: set configs api (#640) --- internal/api/admin/config_manager.go | 79 ++++++++++++++++++++++++++ internal/api/admin/start.go | 1 + pkg/common/apistruct/config_manager.go | 4 ++ 3 files changed, 84 insertions(+) diff --git a/internal/api/admin/config_manager.go b/internal/api/admin/config_manager.go index 75f9b8df9..b9c5dba73 100644 --- a/internal/api/admin/config_manager.go +++ b/internal/api/admin/config_manager.go @@ -15,6 +15,7 @@ import ( "github.com/openimsdk/tools/apiresp" "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/log" + "github.com/openimsdk/tools/utils/datautil" "github.com/openimsdk/tools/utils/runtimeenv" clientv3 "go.etcd.io/etcd/client/v3" ) @@ -109,6 +110,84 @@ func (cm *ConfigManager) SetConfig(c *gin.Context) { apiresp.GinSuccess(c, nil) } +func (cm *ConfigManager) SetConfigs(c *gin.Context) { + if cm.config.Discovery.Enable != kdisc.ETCDCONST { + apiresp.GinError(c, errs.New("only etcd support set config").Wrap()) + return + } + var req apistruct.SetConfigsReq + if err := c.BindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) + return + } + var ( + err error + ops []*clientv3.Op + ) + + for _, cf := range req.Configs { + var op *clientv3.Op + switch cf.ConfigName { + case config.DiscoveryConfigFileName: + op, err = compareAndOp[config.Discovery](c, cm.config.Name2Config(cf.ConfigName), &cf, cm.client) + case config.LogConfigFileName: + op, err = compareAndOp[config.Log](c, cm.config.Name2Config(cf.ConfigName), &cf, cm.client) + case config.MongodbConfigFileName: + op, err = compareAndOp[config.Mongo](c, cm.config.Name2Config(cf.ConfigName), &cf, cm.client) + case config.ChatAPIAdminCfgFileName: + op, err = compareAndOp[config.API](c, cm.config.Name2Config(cf.ConfigName), &cf, cm.client) + case config.ChatAPIChatCfgFileName: + op, err = compareAndOp[config.API](c, cm.config.Name2Config(cf.ConfigName), &cf, cm.client) + case config.ChatRPCAdminCfgFileName: + op, err = compareAndOp[config.Admin](c, cm.config.Name2Config(cf.ConfigName), &cf, cm.client) + case config.ChatRPCChatCfgFileName: + op, err = compareAndOp[config.Chat](c, cm.config.Name2Config(cf.ConfigName), &cf, cm.client) + case config.ShareFileName: + op, err = compareAndOp[config.Share](c, cm.config.Name2Config(cf.ConfigName), &cf, cm.client) + case config.RedisConfigFileName: + op, err = compareAndOp[config.Redis](c, cm.config.Name2Config(cf.ConfigName), &cf, cm.client) + default: + apiresp.GinError(c, errs.ErrArgs.Wrap()) + return + } + if err != nil { + apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) + return + } + if op != nil { + ops = append(ops, op) + } + } + if len(ops) > 0 { + tx := cm.client.Txn(c) + if _, err = tx.Then(datautil.Batch(func(op *clientv3.Op) clientv3.Op { return *op }, ops)...).Commit(); err != nil { + apiresp.GinError(c, errs.WrapMsg(err, "save to etcd failed")) + return + } + + } + + apiresp.GinSuccess(c, nil) +} + +func compareAndOp[T any](c *gin.Context, old any, req *apistruct.SetConfigReq, client *clientv3.Client) (*clientv3.Op, error) { + conf := new(T) + err := json.Unmarshal([]byte(req.Data), &conf) + if err != nil { + return nil, errs.ErrArgs.WithDetail(err.Error()).Wrap() + } + eq := reflect.DeepEqual(old, conf) + if eq { + return nil, nil + } + data, err := json.Marshal(conf) + if err != nil { + return nil, errs.ErrArgs.WithDetail(err.Error()).Wrap() + } + op := clientv3.OpPut(etcd.BuildKey(req.ConfigName), string(data)) + return &op, nil +} + func compareAndSave[T any](c *gin.Context, old any, req *apistruct.SetConfigReq, client *clientv3.Client) error { conf := new(T) err := json.Unmarshal([]byte(req.Data), &conf) diff --git a/internal/api/admin/start.go b/internal/api/admin/start.go index 5ea2bdc1e..880f86cc7 100644 --- a/internal/api/admin/start.go +++ b/internal/api/admin/start.go @@ -208,6 +208,7 @@ func SetAdminRoute(router gin.IRouter, admin *Api, mw *chatmw.MW, cfg *Config, c configGroup.POST("/get_config_list", cm.GetConfigList) configGroup.POST("/get_config", cm.GetConfig) configGroup.POST("/set_config", cm.SetConfig) + configGroup.POST("/set_configs", cm.SetConfigs) configGroup.POST("/reset_config", cm.ResetConfig) configGroup.POST("/get_enable_config_manager", cm.GetEnableConfigManager) configGroup.POST("/set_enable_config_manager", cm.SetEnableConfigManager) diff --git a/pkg/common/apistruct/config_manager.go b/pkg/common/apistruct/config_manager.go index 9b8641c9d..ca5683a3e 100644 --- a/pkg/common/apistruct/config_manager.go +++ b/pkg/common/apistruct/config_manager.go @@ -15,6 +15,10 @@ type SetConfigReq struct { Data string `json:"data"` } +type SetConfigsReq struct { + Configs []SetConfigReq `json:"configs"` +} + type SetEnableConfigManagerReq struct { Enable bool `json:"enable"` } From 2215e7efb13d2eca623797ea5e72272267a8bb63 Mon Sep 17 00:00:00 2001 From: icey-yu <119291641+icey-yu@users.noreply.github.com> Date: Thu, 13 Mar 2025 12:02:32 +0800 Subject: [PATCH 28/36] fix: Incorrect filling rules can also result in errors when not using a phone code (#647) --- internal/rpc/chat/login.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/internal/rpc/chat/login.go b/internal/rpc/chat/login.go index 5c4007d4d..a9df45995 100644 --- a/internal/rpc/chat/login.go +++ b/internal/rpc/chat/login.go @@ -85,6 +85,26 @@ func (o *chatSvr) SendVerifyCode(ctx context.Context, req *chat.SendVerifyCodeRe if o.SMS == nil && o.Mail == nil { return &chat.SendVerifyCodeResp{}, nil // super code } + if req.Email != "" { + switch o.conf.Mail.Use { + case constant.VerifySuperCode: + return &chat.SendVerifyCodeResp{}, nil // super code + case constant.Email: + default: + return nil, errs.ErrInternalServer.WrapMsg("email verification code is not enabled") + } + } + + if req.AreaCode != "" { + switch o.conf.Phone.Use { + case constant.VerifySuperCode: + return &chat.SendVerifyCodeResp{}, nil // super code + case constant.VerifyALi: + default: + return nil, errs.ErrInternalServer.WrapMsg("phone verification code is not enabled") + } + } + isEmail := req.Email != "" var ( code = o.genVerifyCode() From e269e871b7c8993218ce1c404258b7a454bfe713 Mon Sep 17 00:00:00 2001 From: icey-yu <119291641+icey-yu@users.noreply.github.com> Date: Tue, 8 Apr 2025 14:53:13 +0800 Subject: [PATCH 29/36] feat: support harmony (#649) * feat: support harmony * feat: support harmony * feat: support harmony * fix: cicd --- .github/workflows/chat-build-test.yml | 10 +++++++++- go.mod | 6 +++--- go.sum | 22 ++++++++++------------ pkg/protocol/chat/chat.go | 2 +- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/.github/workflows/chat-build-test.yml b/.github/workflows/chat-build-test.yml index c762332ad..a4762a0e8 100644 --- a/.github/workflows/chat-build-test.yml +++ b/.github/workflows/chat-build-test.yml @@ -62,6 +62,10 @@ jobs: sudo sleep 30 # Increased sleep time for better stability timeout-minutes: 30 # Increased timeout for Docker setup + - name: Modify Server Configuration + run: | + yq e '.secret = 123456' -i ${{ github.workspace }}/server-repo/config/share.yml + - name: Build and Start IM Serevr Services run: | cd ${{ github.workspace }}/server-repo @@ -69,6 +73,10 @@ jobs: sudo mage start sudo mage check + - name: Modify Chat Configuration + run: | + yq e '.openIM.secret = 123456' -i config/share.yml + - name: Build, Start, Check Services and Print Logs for Linux run: | sudo mage @@ -135,7 +143,7 @@ jobs: # Test get admin token get_admin_token_response=$(curl -X POST -H "Content-Type: application/json" -H "operationID: imAdmin" -d '{ - "secret": "openIM123", + "secret": "123456", "platformID": 2, "userID": "imAdmin" }' http://127.0.0.1:10002/auth/get_admin_token) diff --git a/go.mod b/go.mod index 2056f0067..8a1b62d4f 100644 --- a/go.mod +++ b/go.mod @@ -11,8 +11,8 @@ require ( github.com/google/uuid v1.6.0 github.com/jinzhu/copier v0.4.0 // indirect github.com/pkg/errors v0.9.1 // indirect - google.golang.org/grpc v1.62.1 - google.golang.org/protobuf v1.34.2 + google.golang.org/grpc v1.68.0 + google.golang.org/protobuf v1.35.1 gopkg.in/yaml.v3 v3.0.1 // indirect gorm.io/gorm v1.25.8 ) @@ -27,7 +27,7 @@ require ( github.com/livekit/protocol v1.10.1 github.com/mitchellh/mapstructure v1.5.0 github.com/openimsdk/gomake v0.0.14-alpha.5 - github.com/openimsdk/protocol v0.0.72 + github.com/openimsdk/protocol v0.0.73-alpha.5 github.com/openimsdk/tools v0.0.50-alpha.65 github.com/redis/go-redis/v9 v9.5.1 github.com/spf13/cobra v1.8.0 diff --git a/go.sum b/go.sum index 76ba8f3a9..31ab5d2c0 100644 --- a/go.sum +++ b/go.sum @@ -215,8 +215,8 @@ github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/openimsdk/gomake v0.0.14-alpha.5 h1:VY9c5x515lTfmdhhPjMvR3BBRrRquAUCFsz7t7vbv7Y= github.com/openimsdk/gomake v0.0.14-alpha.5/go.mod h1:PndCozNc2IsQIciyn9mvEblYWZwJmAI+06z94EY+csI= -github.com/openimsdk/protocol v0.0.72 h1:K+vslwaR7lDXyBzb07UuEQITaqsgighz7NyXVIWsu6A= -github.com/openimsdk/protocol v0.0.72/go.mod h1:OZQA9FR55lseYoN2Ql1XAHYKHJGu7OMNkUbuekrKCM8= +github.com/openimsdk/protocol v0.0.73-alpha.5 h1:SQ7aQRuMJTrUXAoLIu0EIsVU+oIRBvXc7JlA88lEZvw= +github.com/openimsdk/protocol v0.0.73-alpha.5/go.mod h1:WF7EuE55vQvpyUAzDXcqg+B+446xQyEba0X35lTINmw= github.com/openimsdk/tools v0.0.50-alpha.65 h1:BRtxkyWxDWPHuHphSwEyHZj7kJSR98am/fHOH84naK8= github.com/openimsdk/tools v0.0.50-alpha.65/go.mod h1:B+oqV0zdewN7OiEHYJm+hW+8/Te7B8tHHgD8rK5ZLZk= github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= @@ -470,16 +470,14 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ= -google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= -google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 h1:Lj5rbfG876hIAYFjqiJnPHfhXbv+nzTWfm04Fg/XSVU= -google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= -google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= -google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc= +google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0= +google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/pkg/protocol/chat/chat.go b/pkg/protocol/chat/chat.go index ade8b7b1c..52e7ec5d5 100644 --- a/pkg/protocol/chat/chat.go +++ b/pkg/protocol/chat/chat.go @@ -116,7 +116,7 @@ func (x *RegisterUserReq) Check() error { if x.User.Nickname == "" { return errs.ErrArgs.WrapMsg("Nickname is nil") } - if x.Platform < constantpb.IOSPlatformID || x.Platform > constantpb.AdminPlatformID { + if x.Platform < constantpb.IOSPlatformID || x.Platform > constantpb.HarmonyOSPlatformID { return errs.ErrArgs.WrapMsg("platform is invalid") } if x.User == nil { From 28670d2e90537145f4303f2a9ffa922632ea75ad Mon Sep 17 00:00:00 2001 From: Monet Lee Date: Mon, 7 Apr 2025 18:17:05 +0800 Subject: [PATCH 30/36] docs: update config readme. (#650) --- config/README.md | 44 +++++++++++++++++++++++++++++++++++++++++ config/README_zh_CN.md | 45 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 config/README.md create mode 100644 config/README_zh_CN.md diff --git a/config/README.md b/config/README.md new file mode 100644 index 000000000..089831b10 --- /dev/null +++ b/config/README.md @@ -0,0 +1,44 @@ +# OpenIM Chat Configuration Files and Common Configuration Item Modifications Guide + +## Configuration Files Explanation + +| Configuration File | Description | +| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | +| **redis.yml** | Configurations for Redis password, address, etc. | +| **mongodb.yml** | Configurations for MongoDB username, password, address, etc. | +| **share.yml** | Common configurations needed by various OpenIM services, such as secret. | +| **discovery.yml** | Service discovery account, password, service name and other configurations. | +| **chat-api-chat.yml** | Configurations for listening IP, port, etc., in chat-api-chat service. | +| **chat-api-admin.yml** | Configurations for listening IP, port, etc., in chat-api-admin service. | +| **chat-rpc-chat.yml** | Configurations for listening IP, port, login registration verification code, registration allowance, and livekit in chat-rpc-chat service. | +| **chat-rpc-admin.yml** | Configurations for listening IP, port, chat backend token expiration policy, and chat backend Secret in chat-rpc-admin service. | + +## Common Configuration Item Modifications + +| Configuration Item to Modify | Configuration File | +| ----------------------------------------- | -------------------- | +| Modify OpenIM secret | `share.yml` | +| Production environment logs | `log.yml` | +| Modify chat Admin username and password | `share.yml` | +| Modify verification code | `chat-rpc-chat.yml` | +| Allow user registration | `chat-rpc-chat.yml` | +| Modify chat Admin token expiration policy | `chat-rpc-admin.yml` | +| Modify chat Admin Secret | `chat-rpc-admin.yml` | + +## Starting Multiple Instances of an OpenIM Service + +To launch multiple instances of an OpenIM service, you just need to increase the corresponding number of ports and modify the `start-config.yml` file in the project's root directory, then restart the service for the changes to take effect. For example, the configuration for launching 2 instances of `chat-rpc` is as follows: + +```yaml +rpc: + registerIP: "" + listenIP: 0.0.0.0 + ports: [30300, 30301] +``` + +Modify `start-config.yml`: + +```yaml +serviceBinaries: + chat-rpc: 2 +``` diff --git a/config/README_zh_CN.md b/config/README_zh_CN.md new file mode 100644 index 000000000..ecf66e96e --- /dev/null +++ b/config/README_zh_CN.md @@ -0,0 +1,45 @@ +# OpenIM Chat 配置文件说明以及常用配置修改说明 + +## 配置文件说明 + +| Configuration File | Description | +| ---------------------- | ----------------------------------------------------------------------------------------- | +| **redis.yml** | Redis 密码、地址等配置 | +| **mongodb.yml** | MongoDB 用户名、密码、地址等配置 | +| **log.yml** | 日志级别及存储目录等配置 | +| **share.yml** | OpenIM 各服务所需的公共配置,如 secret、Admin 后台密码等 | +| **discovery.yml** | 服务发现对应的账号密码和服务名等配置 | +| **chat-api-chat.yml** | chat-api-chat 服务的监听 IP、端口等配置 | +| **chat-api-admin.yml** | chat-api-admin 服务的监听 IP、端口等配置 | +| **chat-rpc-chat.yml** | chat-rpc-chat.yml 服务的监听 IP、端口以及登录注册验证码、是否允许注册和 livekit 等配置 | +| **chat-rpc-admin.yml** | chat-rpc-admin 服务的监听 IP、端口以及 chat 后台 token 过期策略和 chat 后台 Secret 等配置 | + +## 常用配置修改 + +| 修改配置项 | 配置文件 | +| ----------------------------- | -------------------- | +| 修改 OpenIM secret | `share.yml` | +| 生产环境日志调整 | `log.yml` | +| 修改 chat Admin | `share.yml` | +| 修改验证码相关配置 | `chat-rpc-chat.yml` | +| 允许用户注册 | `chat-rpc-chat.yml` | +| 修改 chat 后台 token 过期策略 | `chat-rpc-admin.yml` | +| 修改 chat 后台 Secret | `chat-rpc-admin.yml` | + +## 启动某个 OpenIM 服务的多个实例 + +若要启动某个 OpenIM 的多个实例,只需增加对应的端口数,并修改项目根目录下的`start-config.yml`文件,重启服务即可生效。例如,启动 2 个`chat-rpc`实例的配置如下: + +```yaml +rpc: + registerIP: "" + listenIP: 0.0.0.0 + ports: [30300, 30301] +``` + +Modify start-config.yml: + +```yaml +serviceBinaries: + chat-rpc: 2 +``` From 7423b203d2e428d23599cb787cd7349f1ac1383a Mon Sep 17 00:00:00 2001 From: icey-yu <119291641+icey-yu@users.noreply.github.com> Date: Wed, 9 Apr 2025 15:23:39 +0800 Subject: [PATCH 31/36] fix: platform check (#652) * feat: support harmony * feat: support harmony * feat: support harmony * fix: cicd * fix: check platform --- pkg/protocol/chat/chat.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/protocol/chat/chat.go b/pkg/protocol/chat/chat.go index ade8b7b1c..0263ae84b 100644 --- a/pkg/protocol/chat/chat.go +++ b/pkg/protocol/chat/chat.go @@ -142,7 +142,7 @@ func (x *RegisterUserReq) Check() error { } func (x *LoginReq) Check() error { - if x.Platform < constantpb.IOSPlatformID || x.Platform > constantpb.AdminPlatformID { + if x.Platform < constantpb.IOSPlatformID || x.Platform > constantpb.HarmonyOSPlatformID { return errs.ErrArgs.WrapMsg("platform is invalid") } if x.Email == "" { From bf2d6b534d45f530ce2355b5d8fc99735bcc21a2 Mon Sep 17 00:00:00 2001 From: icey-yu <119291641+icey-yu@users.noreply.github.com> Date: Thu, 10 Apr 2025 19:04:36 +0800 Subject: [PATCH 32/36] feat: robot module (#654) * feat: robot * fix: create agent * fix: page agent * fix: token * fix: token * fix: token * fix: token * fix: nickname pb * fix: nickname * fix: token log * fix: panic * fix: send log * fix: send log * fix: send ai msg * fix: send ai msg * fix: log * fix: agent * fix: token * fix: update --- cmd/api/bot-api/main.go | 26 + cmd/rpc/bot-rpc/main.go | 26 + config/chat-api-bot.yml | 6 + config/chat-rpc-bot.yml | 10 + config/discovery.yml | 1 + config/share.yml | 2 + go.mod | 15 +- go.sum | 30 +- internal/api/admin/start.go | 7 +- internal/api/bot/bot.go | 177 ++++ internal/api/bot/start.go | 132 +++ internal/api/chat/start.go | 8 +- internal/rpc/bot/agent.go | 153 ++++ internal/rpc/bot/send.go | 95 ++ internal/rpc/bot/start.go | 58 ++ internal/rpc/bot/update.go | 37 + pkg/botstruct/check.go | 11 + pkg/botstruct/const.go | 11 + pkg/botstruct/msg.go | 13 + pkg/common/cmd/bot_api.go | 41 + pkg/common/cmd/bot_rpc.go | 54 ++ pkg/common/cmd/chat_api.go | 1 + pkg/common/config/config.go | 50 +- pkg/common/config/env.go | 2 + pkg/common/constant/user_id.go | 5 + pkg/common/convert/agent.go | 41 + pkg/common/db/cache/imtoken.go | 50 ++ pkg/common/db/cache/token.go | 5 +- pkg/common/db/database/bot.go | 77 ++ pkg/common/db/database/imtoken.go | 31 + pkg/common/db/model/bot/agent.go | 65 ++ .../db/model/bot/conversation_resp_id.go | 50 ++ pkg/common/db/table/bot/agent.go | 33 + .../db/table/bot/conversation_resp_id.go | 22 + pkg/common/imapi/api.go | 29 +- pkg/common/imapi/call.go | 62 +- pkg/common/imapi/caller.go | 89 +- pkg/common/imapi/model.go | 13 + pkg/common/imwebhook/message.go | 48 + pkg/protocol/bot/bot.pb.go | 829 ++++++++++++++++++ pkg/protocol/bot/bot.proto | 73 ++ pkg/protocol/bot/bot_grpc.pb.go | 273 ++++++ pkg/protocol/gen.cmd | 2 +- start-config.yml | 2 + tools/check-component/main.go | 12 +- 45 files changed, 2721 insertions(+), 56 deletions(-) create mode 100644 cmd/api/bot-api/main.go create mode 100644 cmd/rpc/bot-rpc/main.go create mode 100644 config/chat-api-bot.yml create mode 100644 config/chat-rpc-bot.yml create mode 100644 internal/api/bot/bot.go create mode 100644 internal/api/bot/start.go create mode 100644 internal/rpc/bot/agent.go create mode 100644 internal/rpc/bot/send.go create mode 100644 internal/rpc/bot/start.go create mode 100644 internal/rpc/bot/update.go create mode 100644 pkg/botstruct/check.go create mode 100644 pkg/botstruct/const.go create mode 100644 pkg/botstruct/msg.go create mode 100644 pkg/common/cmd/bot_api.go create mode 100644 pkg/common/cmd/bot_rpc.go create mode 100644 pkg/common/constant/user_id.go create mode 100644 pkg/common/convert/agent.go create mode 100644 pkg/common/db/cache/imtoken.go create mode 100644 pkg/common/db/database/bot.go create mode 100644 pkg/common/db/database/imtoken.go create mode 100644 pkg/common/db/model/bot/agent.go create mode 100644 pkg/common/db/model/bot/conversation_resp_id.go create mode 100644 pkg/common/db/table/bot/agent.go create mode 100644 pkg/common/db/table/bot/conversation_resp_id.go create mode 100644 pkg/common/imapi/model.go create mode 100644 pkg/common/imwebhook/message.go create mode 100644 pkg/protocol/bot/bot.pb.go create mode 100644 pkg/protocol/bot/bot.proto create mode 100644 pkg/protocol/bot/bot_grpc.pb.go diff --git a/cmd/api/bot-api/main.go b/cmd/api/bot-api/main.go new file mode 100644 index 000000000..e70a7c298 --- /dev/null +++ b/cmd/api/bot-api/main.go @@ -0,0 +1,26 @@ +// Copyright © 2023 OpenIM open source community. 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 ( + "github.com/openimsdk/chat/pkg/common/cmd" + "github.com/openimsdk/tools/system/program" +) + +func main() { + if err := cmd.NewBotApiCmd().Exec(); err != nil { + program.ExitWithError(err) + } +} diff --git a/cmd/rpc/bot-rpc/main.go b/cmd/rpc/bot-rpc/main.go new file mode 100644 index 000000000..65b19609b --- /dev/null +++ b/cmd/rpc/bot-rpc/main.go @@ -0,0 +1,26 @@ +// Copyright © 2023 OpenIM open source community. 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 ( + "github.com/openimsdk/chat/pkg/common/cmd" + "github.com/openimsdk/tools/system/program" +) + +func main() { + if err := cmd.NewBotRpcCmd().Exec(); err != nil { + program.ExitWithError(err) + } +} diff --git a/config/chat-api-bot.yml b/config/chat-api-bot.yml new file mode 100644 index 000000000..cc401af03 --- /dev/null +++ b/config/chat-api-bot.yml @@ -0,0 +1,6 @@ +api: + # Listening IP; 0.0.0.0 means both internal and external IPs are listened to, default is recommended + listenIP: 0.0.0.0 + # Listening ports; if multiple are configured, multiple instances will be launched + ports: [ 10010 ] + diff --git a/config/chat-rpc-bot.yml b/config/chat-rpc-bot.yml new file mode 100644 index 000000000..3d8d8c6f2 --- /dev/null +++ b/config/chat-rpc-bot.yml @@ -0,0 +1,10 @@ +rpc: + # The IP address where this RPC service registers itself; if left blank, it defaults to the internal network IP + registerIP: '' + # IP address that the RPC service listens on; setting to 0.0.0.0 listens on both internal and external IPs. If left blank, it automatically uses the internal network IP + listenIP: 0.0.0.0 + # List of ports that the RPC service listens on; configuring multiple ports will launch multiple instances. + ports: [ 30400 ] + +# Model request timeout. Unit: s +timeout: 20 diff --git a/config/discovery.yml b/config/discovery.yml index 1c34af784..5022a6abb 100644 --- a/config/discovery.yml +++ b/config/discovery.yml @@ -11,3 +11,4 @@ kubernetes: rpcService: chat: chat-rpc-service admin: admin-rpc-service + bot: bot-rpc-service diff --git a/config/share.yml b/config/share.yml index 907b569ca..20ea77b54 100644 --- a/config/share.yml +++ b/config/share.yml @@ -5,6 +5,8 @@ openIM: secret: openIM123 # OpenIM administrator userID, must be consistent with OpenIM adminUserID: imAdmin + # Refresh OpenIM token interval + tokenRefreshInterval: 120 # unit: minute chatAdmin: # Default username and password for the admin diff --git a/go.mod b/go.mod index 2056f0067..be90c0f4b 100644 --- a/go.mod +++ b/go.mod @@ -30,11 +30,13 @@ require ( github.com/openimsdk/protocol v0.0.72 github.com/openimsdk/tools v0.0.50-alpha.65 github.com/redis/go-redis/v9 v9.5.1 + github.com/sashabaranov/go-openai v1.38.1 github.com/spf13/cobra v1.8.0 github.com/spf13/viper v1.18.2 github.com/xuri/excelize/v2 v2.8.0 go.etcd.io/etcd/client/v3 v3.5.13 go.mongodb.org/mongo-driver v1.14.0 + golang.org/x/sync v0.10.0 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df ) @@ -123,14 +125,13 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/arch v0.3.0 // indirect - golang.org/x/crypto v0.24.0 // indirect + golang.org/x/crypto v0.32.0 // indirect golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect - golang.org/x/net v0.26.0 // indirect - golang.org/x/oauth2 v0.21.0 // indirect - golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.21.0 // indirect - golang.org/x/term v0.21.0 // indirect - golang.org/x/text v0.16.0 // indirect + golang.org/x/net v0.34.0 // indirect + golang.org/x/oauth2 v0.23.0 // indirect + golang.org/x/sys v0.29.0 // indirect + golang.org/x/term v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 // indirect diff --git a/go.sum b/go.sum index 76ba8f3a9..79e38c991 100644 --- a/go.sum +++ b/go.sum @@ -282,6 +282,8 @@ github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6ke github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sashabaranov/go-openai v1.38.1 h1:TtZabbFQZa1nEni/IhVtDF/WQjVqDgd+cWR5OeddzF8= +github.com/sashabaranov/go-openai v1.38.1/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= @@ -380,8 +382,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= -golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8= @@ -403,18 +405,18 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= -golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= -golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -431,8 +433,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -440,8 +442,8 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= -golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= +golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= +golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -452,8 +454,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/internal/api/admin/start.go b/internal/api/admin/start.go index 5ea2bdc1e..7f8f468aa 100644 --- a/internal/api/admin/start.go +++ b/internal/api/admin/start.go @@ -19,6 +19,7 @@ import ( disetcd "github.com/openimsdk/chat/pkg/common/kdisc/etcd" adminclient "github.com/openimsdk/chat/pkg/protocol/admin" chatclient "github.com/openimsdk/chat/pkg/protocol/chat" + "github.com/openimsdk/tools/db/redisutil" "github.com/openimsdk/tools/discovery" "github.com/openimsdk/tools/discovery/etcd" "github.com/openimsdk/tools/errs" @@ -52,6 +53,10 @@ func Start(ctx context.Context, index int, config *Config) error { if err != nil { return err } + rdb, err := redisutil.NewRedisClient(ctx, config.Redis.Build()) + if err != nil { + return err + } chatConn, err := client.GetConn(ctx, config.Discovery.RpcService.Chat, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) if err != nil { @@ -63,7 +68,7 @@ func Start(ctx context.Context, index int, config *Config) error { } chatClient := chatclient.NewChatClient(chatConn) adminClient := adminclient.NewAdminClient(adminConn) - im := imapi.New(config.Share.OpenIM.ApiURL, config.Share.OpenIM.Secret, config.Share.OpenIM.AdminUserID) + im := imapi.New(config.Share.OpenIM.ApiURL, config.Share.OpenIM.Secret, config.Share.OpenIM.AdminUserID, rdb, config.Share.OpenIM.TokenRefreshInterval) base := util.Api{ ImUserID: config.Share.OpenIM.AdminUserID, ProxyHeader: config.Share.ProxyHeader, diff --git a/internal/api/bot/bot.go b/internal/api/bot/bot.go new file mode 100644 index 000000000..952aafbc6 --- /dev/null +++ b/internal/api/bot/bot.go @@ -0,0 +1,177 @@ +package bot + +import ( + "encoding/json" + "sort" + "strings" + + "github.com/gin-gonic/gin" + "github.com/openimsdk/chat/internal/api/util" + "github.com/openimsdk/chat/pkg/botstruct" + "github.com/openimsdk/chat/pkg/common/imwebhook" + "github.com/openimsdk/chat/pkg/protocol/bot" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/tools/a2r" + "github.com/openimsdk/tools/apiresp" + "github.com/openimsdk/tools/errs" + "golang.org/x/sync/errgroup" +) + +func New(botClient bot.BotClient, api *util.Api) *Api { + return &Api{ + Api: api, + botClient: botClient, + } +} + +type Api struct { + *util.Api + botClient bot.BotClient +} + +func (o *Api) CreateAgent(c *gin.Context) { + a2r.Call(c, bot.BotClient.CreateAgent, o.botClient) +} + +func (o *Api) DeleteAgent(c *gin.Context) { + a2r.Call(c, bot.BotClient.DeleteAgent, o.botClient) +} + +func (o *Api) UpdateAgent(c *gin.Context) { + a2r.Call(c, bot.BotClient.UpdateAgent, o.botClient) +} + +func (o *Api) PageFindAgent(c *gin.Context) { + a2r.Call(c, bot.BotClient.PageFindAgent, o.botClient) +} + +func (o *Api) AfterSendSingleMsg(c *gin.Context) { + var ( + req = imwebhook.CallbackAfterSendSingleMsgReq{} + ) + + if err := c.BindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) + return + } + if req.ContentType != constant.Text { + apiresp.GinSuccess(c, nil) + return + } + isAgent := botstruct.IsAgentUserID(req.RecvID) + if !isAgent { + apiresp.GinSuccess(c, nil) + return + } + + var elem botstruct.TextElem + err := json.Unmarshal([]byte(req.Content), &elem) + if err != nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("json unmarshal error: "+err.Error())) + return + } + convID := getConversationIDByMsg(req.SessionType, req.SendID, req.RecvID, "") + + key, ok := c.GetQuery(botstruct.Key) + if !ok { + apiresp.GinError(c, errs.ErrArgs.WithDetail("missing key in query").Wrap()) + return + } + res, err := o.botClient.SendBotMessage(c, &bot.SendBotMessageReq{ + AgentID: req.RecvID, + ConversationID: convID, + ContentType: req.ContentType, + Content: elem.Content, + Ex: req.Ex, + Key: key, + }) + if err != nil { + apiresp.GinError(c, err) + return + } + apiresp.GinSuccess(c, res) +} + +func (o *Api) AfterSendGroupMsg(c *gin.Context) { + var ( + req = imwebhook.CallbackAfterSendSingleMsgReq{} + ) + if err := c.BindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) + return + } + + if req.ContentType != constant.AtText { + apiresp.GinSuccess(c, nil) + } + key, ok := c.GetQuery(botstruct.Key) + if !ok { + apiresp.GinError(c, errs.ErrArgs.WithDetail("missing key in query").Wrap()) + return + } + + var ( + elem botstruct.AtElem + reqs []*bot.SendBotMessageReq + ) + + convID := getConversationIDByMsg(req.SessionType, req.SendID, req.RecvID, "") + err := json.Unmarshal([]byte(req.Content), &elem) + if err != nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("json unmarshal error: "+err.Error())) + } + for _, userID := range elem.AtUserList { + if botstruct.IsAgentUserID(userID) { + reqs = append(reqs, &bot.SendBotMessageReq{ + AgentID: userID, + ConversationID: convID, + ContentType: req.ContentType, + Content: elem.Text, + Ex: req.Ex, + Key: key, + }) + } + } + if len(reqs) == 0 { + apiresp.GinSuccess(c, nil) + } + + g := errgroup.Group{} + g.SetLimit(min(len(reqs), 5)) + for i := 0; i < len(reqs); i++ { + i := i + g.Go(func() error { + _, err := o.botClient.SendBotMessage(c, reqs[i]) + if err != nil { + return err + } + return nil + }) + } + + err = g.Wait() + if err != nil { + apiresp.GinError(c, err) + return + } + + apiresp.GinSuccess(c, nil) +} + +func getConversationIDByMsg(sessionType int32, sendID, recvID, groupID string) string { + switch sessionType { + case constant.SingleChatType: + l := []string{sendID, recvID} + sort.Strings(l) + return "si_" + strings.Join(l, "_") // single chat + case constant.WriteGroupChatType: + return "g_" + groupID // group chat + case constant.ReadGroupChatType: + return "sg_" + groupID // super group chat + case constant.NotificationChatType: + l := []string{sendID, recvID} + sort.Strings(l) + return "sn_" + strings.Join(l, "_") + } + return "" +} diff --git a/internal/api/bot/start.go b/internal/api/bot/start.go new file mode 100644 index 000000000..b840d1139 --- /dev/null +++ b/internal/api/bot/start.go @@ -0,0 +1,132 @@ +package bot + +import ( + "context" + "errors" + "fmt" + "net/http" + "os" + "os/signal" + "syscall" + "time" + + "github.com/gin-gonic/gin" + chatmw "github.com/openimsdk/chat/internal/api/mw" + "github.com/openimsdk/chat/internal/api/util" + "github.com/openimsdk/chat/pkg/common/config" + "github.com/openimsdk/chat/pkg/common/kdisc" + disetcd "github.com/openimsdk/chat/pkg/common/kdisc/etcd" + adminclient "github.com/openimsdk/chat/pkg/protocol/admin" + botclient "github.com/openimsdk/chat/pkg/protocol/bot" + "github.com/openimsdk/tools/discovery/etcd" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/mw" + "github.com/openimsdk/tools/system/program" + "github.com/openimsdk/tools/utils/datautil" + "github.com/openimsdk/tools/utils/runtimeenv" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +type Config struct { + ApiConfig config.APIBot + Discovery config.Discovery + Share config.Share + Redis config.Redis + + RuntimeEnv string +} + +func Start(ctx context.Context, index int, cfg *Config) error { + cfg.RuntimeEnv = runtimeenv.PrintRuntimeEnvironment() + apiPort, err := datautil.GetElemByIndex(cfg.ApiConfig.Api.Ports, index) + if err != nil { + return err + } + client, err := kdisc.NewDiscoveryRegister(&cfg.Discovery, cfg.RuntimeEnv, nil) + if err != nil { + return err + } + + botConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Bot, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) + if err != nil { + return err + } + adminConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Admin, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) + if err != nil { + return err + } + adminClient := adminclient.NewAdminClient(adminConn) + botClient := botclient.NewBotClient(botConn) + base := util.Api{ + ImUserID: cfg.Share.OpenIM.AdminUserID, + ProxyHeader: cfg.Share.ProxyHeader, + ChatAdminUserID: cfg.Share.ChatAdmin[0], + } + botApi := New(botClient, &base) + mwApi := chatmw.New(adminClient) + gin.SetMode(gin.ReleaseMode) + engine := gin.New() + engine.Use(gin.Recovery(), mw.CorsHandler(), mw.GinParseOperationID()) + SetBotRoute(engine, botApi, mwApi) + + var ( + netDone = make(chan struct{}, 1) + netErr error + ) + server := http.Server{Addr: fmt.Sprintf(":%d", apiPort), Handler: engine} + go func() { + err = server.ListenAndServe() + if err != nil && !errors.Is(err, http.ErrServerClosed) { + netErr = errs.WrapMsg(err, fmt.Sprintf("api start err: %s", server.Addr)) + netDone <- struct{}{} + } + }() + if cfg.Discovery.Enable == kdisc.ETCDCONST { + cm := disetcd.NewConfigManager(client.(*etcd.SvcDiscoveryRegistryImpl).GetClient(), + []string{ + config.ChatAPIBotCfgFileName, + config.DiscoveryConfigFileName, + config.ShareFileName, + config.LogConfigFileName, + }, + ) + cm.Watch(ctx) + } + shutdown := func() error { + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + err := server.Shutdown(ctx) + if err != nil { + return errs.WrapMsg(err, "shutdown err") + } + return nil + } + disetcd.RegisterShutDown(shutdown) + + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, syscall.SIGTERM) + select { + case <-sigs: + program.SIGTERMExit() + if err := shutdown(); err != nil { + return err + } + case <-netDone: + close(netDone) + return netErr + } + return nil +} + +func SetBotRoute(router gin.IRouter, bot *Api, mw *chatmw.MW) { + account := router.Group("/agent") + account.POST("/create", mw.CheckAdmin, bot.CreateAgent) + account.POST("/delete", mw.CheckAdmin, bot.DeleteAgent) + account.POST("/update", mw.CheckAdmin, bot.UpdateAgent) + account.POST("/page", mw.CheckToken, bot.PageFindAgent) + + imwebhook := router.Group("/im_callback") + imwebhook.POST("/callbackAfterSendSingleMsgCommand", bot.AfterSendSingleMsg) + imwebhook.POST("/callbackAfterSendGroupMsgCommand", bot.AfterSendGroupMsg) +} diff --git a/internal/api/chat/start.go b/internal/api/chat/start.go index df14893c0..feb32a051 100644 --- a/internal/api/chat/start.go +++ b/internal/api/chat/start.go @@ -19,6 +19,7 @@ import ( disetcd "github.com/openimsdk/chat/pkg/common/kdisc/etcd" adminclient "github.com/openimsdk/chat/pkg/protocol/admin" chatclient "github.com/openimsdk/chat/pkg/protocol/chat" + "github.com/openimsdk/tools/db/redisutil" "github.com/openimsdk/tools/discovery/etcd" "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/mw" @@ -33,6 +34,7 @@ type Config struct { ApiConfig config.API Discovery config.Discovery Share config.Share + Redis config.Redis RuntimeEnv string } @@ -51,6 +53,10 @@ func Start(ctx context.Context, index int, cfg *Config) error { if err != nil { return err } + rdb, err := redisutil.NewRedisClient(ctx, cfg.Redis.Build()) + if err != nil { + return err + } chatConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Chat, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient()) if err != nil { @@ -62,7 +68,7 @@ func Start(ctx context.Context, index int, cfg *Config) error { } chatClient := chatclient.NewChatClient(chatConn) adminClient := adminclient.NewAdminClient(adminConn) - im := imapi.New(cfg.Share.OpenIM.ApiURL, cfg.Share.OpenIM.Secret, cfg.Share.OpenIM.AdminUserID) + im := imapi.New(cfg.Share.OpenIM.ApiURL, cfg.Share.OpenIM.Secret, cfg.Share.OpenIM.AdminUserID, rdb, cfg.Share.OpenIM.TokenRefreshInterval) base := util.Api{ ImUserID: cfg.Share.OpenIM.AdminUserID, ProxyHeader: cfg.Share.ProxyHeader, diff --git a/internal/rpc/bot/agent.go b/internal/rpc/bot/agent.go new file mode 100644 index 000000000..c04d604fe --- /dev/null +++ b/internal/rpc/bot/agent.go @@ -0,0 +1,153 @@ +package bot + +import ( + "context" + "crypto/rand" + "time" + + "github.com/openimsdk/chat/pkg/common/constant" + "github.com/openimsdk/chat/pkg/common/convert" + "github.com/openimsdk/chat/pkg/common/mctx" + "github.com/openimsdk/chat/pkg/protocol/bot" + pbconstant "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/protocol/sdkws" + "github.com/openimsdk/protocol/user" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/utils/datautil" +) + +func (b *botSvr) CreateAgent(ctx context.Context, req *bot.CreateAgentReq) (*bot.CreateAgentResp, error) { + if req.Agent == nil { + return nil, errs.ErrArgs.WrapMsg("req.Agent is nil") + } + + now := time.Now() + imToken, err := b.imCaller.ImAdminTokenWithDefaultAdmin(ctx) + if err != nil { + return nil, err + } + ctx = mctx.WithApiToken(ctx, imToken) + if req.Agent.UserID != "" { + req.Agent.UserID = constant.AgentUserIDPrefix + req.Agent.UserID + users, err := b.imCaller.GetUsersInfo(ctx, []string{req.Agent.UserID}) + if err != nil { + return nil, err + } + if len(users) > 0 { + return nil, errs.ErrDuplicateKey.WrapMsg("agent userID already exists") + } + } else { + randUserIDs := make([]string, 5) + for i := range randUserIDs { + randUserIDs[i] = constant.AgentUserIDPrefix + genID(10) + } + users, err := b.imCaller.GetUsersInfo(ctx, randUserIDs) + if err != nil { + return nil, err + } + if len(users) == len(randUserIDs) { + return nil, errs.ErrDuplicateKey.WrapMsg("gen agent userID already exists, please try again") + } + userIDs := datautil.Batch(func(u *sdkws.UserInfo) string { return u.UserID }, users) + for _, uid := range randUserIDs { + if datautil.Contain(uid, userIDs...) { + continue + } + req.Agent.UserID = uid + break + } + } + + if err := b.imCaller.AddNotificationAccount(ctx, &user.AddNotificationAccountReq{ + UserID: req.Agent.UserID, + NickName: req.Agent.Nickname, + FaceURL: req.Agent.FaceURL, + AppMangerLevel: pbconstant.AppRobotAdmin, + }); err != nil { + return nil, err + } + dbagent := convert.PB2DBAgent(req.Agent) + dbagent.CreateTime = now + err = b.database.CreateAgent(ctx, dbagent) + if err != nil { + return nil, err + } + return &bot.CreateAgentResp{}, nil +} + +func (b *botSvr) UpdateAgent(ctx context.Context, req *bot.UpdateAgentReq) (*bot.UpdateAgentResp, error) { + if _, err := b.database.TakeAgent(ctx, req.UserID); err != nil { + return nil, errs.ErrArgs.Wrap() + } + + if req.FaceURL != nil || req.Nickname != nil { + imReq := &user.UpdateNotificationAccountInfoReq{ + UserID: req.UserID, + } + if req.Nickname != nil { + imReq.NickName = *req.Nickname + } + if req.FaceURL != nil { + imReq.FaceURL = *req.FaceURL + } + imToken, err := b.imCaller.ImAdminTokenWithDefaultAdmin(ctx) + if err != nil { + return nil, err + } + ctx = mctx.WithApiToken(ctx, imToken) + err = b.imCaller.UpdateNotificationAccount(ctx, imReq) + if err != nil { + return nil, err + } + } + + update := ToDBAgentUpdate(req) + err := b.database.UpdateAgent(ctx, req.UserID, update) + if err != nil { + return nil, err + } + + return &bot.UpdateAgentResp{}, nil +} + +func (b *botSvr) PageFindAgent(ctx context.Context, req *bot.PageFindAgentReq) (*bot.PageFindAgentResp, error) { + total, agents, err := b.database.PageAgents(ctx, req.UserIDs, req.Pagination) + if err != nil { + return nil, err + } + //_, userType, err := mctx.Check(ctx) + //if err != nil { + // return nil, err + //} + //if userType != constant.AdminUser { + for i := range agents { + agents[i].Key = "" + } + //} + return &bot.PageFindAgentResp{ + Total: total, + Agents: convert.BatchDB2PBAgent(agents), + }, nil +} + +func (b *botSvr) DeleteAgent(ctx context.Context, req *bot.DeleteAgentReq) (*bot.DeleteAgentResp, error) { + err := b.database.DeleteAgents(ctx, req.UserIDs) + if err != nil { + return nil, err + } + return &bot.DeleteAgentResp{}, nil +} + +func genID(l int) string { + data := make([]byte, l) + _, _ = rand.Read(data) + chars := []byte("0123456789") + for i := 0; i < len(data); i++ { + if i == 0 { + data[i] = chars[1:][data[i]%9] + } else { + data[i] = chars[data[i]%10] + } + } + return string(data) +} diff --git a/internal/rpc/bot/send.go b/internal/rpc/bot/send.go new file mode 100644 index 000000000..88cc9c17b --- /dev/null +++ b/internal/rpc/bot/send.go @@ -0,0 +1,95 @@ +package bot + +import ( + "context" + "encoding/json" + "errors" + "time" + + "github.com/openimsdk/chat/pkg/botstruct" + "github.com/openimsdk/chat/pkg/common/imapi" + "github.com/openimsdk/chat/pkg/common/mctx" + "github.com/openimsdk/chat/pkg/protocol/bot" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/tools/errs" + "github.com/sashabaranov/go-openai" + "go.mongodb.org/mongo-driver/mongo" +) + +func (b *botSvr) SendBotMessage(ctx context.Context, req *bot.SendBotMessageReq) (*bot.SendBotMessageResp, error) { + agent, err := b.database.TakeAgent(ctx, req.AgentID) + if err != nil { + return nil, errs.ErrArgs.WrapMsg("agent not found") + } + convRespID, err := b.database.TakeConversationRespID(ctx, req.ConversationID, req.AgentID) + if err != nil && !errors.Is(err, mongo.ErrNoDocuments) { + return nil, err + } + var respID string + if convRespID != nil { + respID = convRespID.PreviousResponseID + } + + aiCfg := openai.DefaultConfig(agent.Key) + aiCfg.BaseURL = agent.Url + aiCfg.HTTPClient = b.httpClient + aiCfg.OrgID = respID + client := openai.NewClientWithConfig(aiCfg) + aiReq := openai.ChatCompletionRequest{ + Model: agent.Model, + Messages: []openai.ChatCompletionMessage{ + { + Role: openai.ChatMessageRoleSystem, + Content: agent.Prompts, + }, + { + Role: openai.ChatMessageRoleUser, + Content: req.Content, + }, + }, + } + aiCtx, cancel := context.WithTimeout(ctx, time.Duration(b.timeout)*time.Second) + defer cancel() + completion, err := client.CreateChatCompletion(aiCtx, aiReq) + if err != nil { + return nil, errs.Wrap(err) + } + + imToken, err := b.imCaller.ImAdminTokenWithDefaultAdmin(ctx) + if err != nil { + return nil, err + } + ctx = mctx.WithApiToken(ctx, imToken) + + content := "no response" + if len(completion.Choices) > 0 { + content = completion.Choices[0].Message.Content + } + err = b.imCaller.SendSimpleMsg(ctx, &imapi.SendSingleMsgReq{ + SendID: agent.UserID, + Content: content, + }, req.Key) + if err != nil { + return nil, err + } + + err = b.database.UpdateConversationRespID(ctx, req.ConversationID, agent.UserID, ToDBConversationRespIDUpdate(completion.ID)) + if err != nil { + return nil, err + } + return &bot.SendBotMessageResp{}, nil +} + +func getContent(contentType int32, content string) (string, error) { + switch contentType { + case constant.Text: + var elem botstruct.TextElem + err := json.Unmarshal([]byte(content), &elem) + if err != nil { + return "", errs.ErrArgs.WrapMsg(err.Error()) + } + return elem.Content, nil + default: + return "", errs.New("un support contentType").Wrap() + } +} diff --git a/internal/rpc/bot/start.go b/internal/rpc/bot/start.go new file mode 100644 index 000000000..da3108cf5 --- /dev/null +++ b/internal/rpc/bot/start.go @@ -0,0 +1,58 @@ +package bot + +import ( + "context" + "net/http" + "time" + + "github.com/openimsdk/chat/pkg/common/config" + "github.com/openimsdk/chat/pkg/common/db/database" + "github.com/openimsdk/chat/pkg/common/imapi" + "github.com/openimsdk/chat/pkg/protocol/bot" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/redisutil" + "github.com/openimsdk/tools/discovery" + "google.golang.org/grpc" +) + +type Config struct { + RpcConfig config.Bot + RedisConfig config.Redis + MongodbConfig config.Mongo + Discovery config.Discovery + Share config.Share +} + +func Start(ctx context.Context, config *Config, client discovery.SvcDiscoveryRegistry, server *grpc.Server) error { + mgocli, err := mongoutil.NewMongoDB(ctx, config.MongodbConfig.Build()) + if err != nil { + return err + } + var srv botSvr + rdb, err := redisutil.NewRedisClient(ctx, config.RedisConfig.Build()) + if err != nil { + return err + } + + srv.database, err = database.NewBotDatabase(mgocli) + if err != nil { + return err + } + srv.timeout = config.RpcConfig.Timeout + srv.httpClient = &http.Client{ + Timeout: time.Duration(config.RpcConfig.Timeout) * time.Second, + } + im := imapi.New(config.Share.OpenIM.ApiURL, config.Share.OpenIM.Secret, config.Share.OpenIM.AdminUserID, rdb, config.Share.OpenIM.TokenRefreshInterval) + srv.imCaller = im + bot.RegisterBotServer(server, &srv) + return nil +} + +type botSvr struct { + bot.UnimplementedBotServer + database database.BotDatabase + httpClient *http.Client + timeout int + imCaller imapi.CallerInterface + //Admin *chatClient.AdminClient +} diff --git a/internal/rpc/bot/update.go b/internal/rpc/bot/update.go new file mode 100644 index 000000000..84a4fd6b4 --- /dev/null +++ b/internal/rpc/bot/update.go @@ -0,0 +1,37 @@ +package bot + +import "github.com/openimsdk/chat/pkg/protocol/bot" + +func ToDBAgentUpdate(req *bot.UpdateAgentReq) map[string]any { + update := make(map[string]any) + if req.Key != nil { + update["key"] = req.Key + } + if req.Prompts != nil { + update["prompts"] = req.Prompts + } + if req.Model != nil { + update["model"] = req.Model + } + if req.FaceURL != nil { + update["face_url"] = req.FaceURL + } + if req.Nickname != nil { + update["nick_name"] = req.Nickname + } + if req.Identity != nil { + update["identity"] = req.Identity + } + if req.Url != nil { + update["url"] = req.Url + } + + return update +} + +func ToDBConversationRespIDUpdate(respID string) map[string]any { + update := map[string]any{ + "previous_response_id": respID, + } + return update +} diff --git a/pkg/botstruct/check.go b/pkg/botstruct/check.go new file mode 100644 index 000000000..7032de389 --- /dev/null +++ b/pkg/botstruct/check.go @@ -0,0 +1,11 @@ +package botstruct + +import ( + "strings" + + "github.com/openimsdk/chat/pkg/common/constant" +) + +func IsAgentUserID(userID string) bool { + return strings.HasPrefix(userID, constant.AgentUserIDPrefix) +} diff --git a/pkg/botstruct/const.go b/pkg/botstruct/const.go new file mode 100644 index 000000000..ac5296fe9 --- /dev/null +++ b/pkg/botstruct/const.go @@ -0,0 +1,11 @@ +package botstruct + +const ( + Key = "key" + AgentIDPrefix = "agent_" +) + +const ( + RoleDeveloper = "developer" + RoleUser = "user" +) diff --git a/pkg/botstruct/msg.go b/pkg/botstruct/msg.go new file mode 100644 index 000000000..053269e48 --- /dev/null +++ b/pkg/botstruct/msg.go @@ -0,0 +1,13 @@ +package botstruct + +// see openim-sdk-core\sdk_struct\sdk_struct.go + +type TextElem struct { + Content string `json:"content"` +} + +type AtElem struct { + Text string `mapstructure:"text"` + AtUserList []string `mapstructure:"atUserList" validate:"required,max=1000"` + IsAtSelf bool `mapstructure:"isAtSelf"` +} diff --git a/pkg/common/cmd/bot_api.go b/pkg/common/cmd/bot_api.go new file mode 100644 index 000000000..a8577a175 --- /dev/null +++ b/pkg/common/cmd/bot_api.go @@ -0,0 +1,41 @@ +package cmd + +import ( + "context" + + "github.com/openimsdk/chat/internal/api/bot" + "github.com/openimsdk/chat/pkg/common/config" + "github.com/openimsdk/tools/system/program" + "github.com/spf13/cobra" +) + +type BotApiCmd struct { + *RootCmd + ctx context.Context + configMap map[string]any + apiConfig bot.Config +} + +func NewBotApiCmd() *BotApiCmd { + ret := BotApiCmd{apiConfig: bot.Config{}} + ret.configMap = map[string]any{ + config.DiscoveryConfigFileName: &ret.apiConfig.Discovery, + config.ChatAPIBotCfgFileName: &ret.apiConfig.ApiConfig, + config.ShareFileName: &ret.apiConfig.Share, + config.RedisConfigFileName: &ret.apiConfig.Redis, + } + ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap)) + ret.ctx = context.WithValue(context.Background(), "version", config.Version) + ret.Command.RunE = func(cmd *cobra.Command, args []string) error { + return ret.runE() + } + return &ret +} + +func (a *BotApiCmd) Exec() error { + return a.Execute() +} + +func (a *BotApiCmd) runE() error { + return bot.Start(a.ctx, a.Index(), &a.apiConfig) +} diff --git a/pkg/common/cmd/bot_rpc.go b/pkg/common/cmd/bot_rpc.go new file mode 100644 index 000000000..c05c382b4 --- /dev/null +++ b/pkg/common/cmd/bot_rpc.go @@ -0,0 +1,54 @@ +package cmd + +import ( + "context" + + "github.com/openimsdk/chat/internal/rpc/bot" + "github.com/openimsdk/chat/pkg/common/config" + "github.com/openimsdk/chat/pkg/common/startrpc" + "github.com/openimsdk/tools/system/program" + "github.com/spf13/cobra" +) + +type BotRpcCmd struct { + *RootCmd + ctx context.Context + configMap map[string]any + botConfig bot.Config +} + +func NewBotRpcCmd() *BotRpcCmd { + var ret BotRpcCmd + ret.configMap = map[string]any{ + config.ChatRPCBotCfgFileName: &ret.botConfig.RpcConfig, + config.RedisConfigFileName: &ret.botConfig.RedisConfig, + config.DiscoveryConfigFileName: &ret.botConfig.Discovery, + config.MongodbConfigFileName: &ret.botConfig.MongodbConfig, + config.ShareFileName: &ret.botConfig.Share, + } + ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap)) + ret.ctx = context.WithValue(context.Background(), "version", config.Version) + ret.Command.RunE = func(cmd *cobra.Command, args []string) error { + return ret.runE() + } + return &ret +} + +func (a *BotRpcCmd) Exec() error { + return a.Execute() +} + +func (a *BotRpcCmd) runE() error { + return startrpc.Start(a.ctx, &a.botConfig.Discovery, a.botConfig.RpcConfig.RPC.ListenIP, + a.botConfig.RpcConfig.RPC.RegisterIP, a.botConfig.RpcConfig.RPC.Ports, + a.Index(), a.botConfig.Discovery.RpcService.Bot, &a.botConfig.Share, &a.botConfig, + []string{ + config.ChatRPCBotCfgFileName, + config.RedisConfigFileName, + config.DiscoveryConfigFileName, + config.MongodbConfigFileName, + config.ShareFileName, + config.LogConfigFileName, + }, nil, + bot.Start) +} diff --git a/pkg/common/cmd/chat_api.go b/pkg/common/cmd/chat_api.go index 9c8da44e3..7dfad92ec 100644 --- a/pkg/common/cmd/chat_api.go +++ b/pkg/common/cmd/chat_api.go @@ -22,6 +22,7 @@ func NewChatApiCmd() *ChatApiCmd { config.ShareFileName: &ret.apiConfig.Share, config.ChatAPIChatCfgFileName: &ret.apiConfig.ApiConfig, config.DiscoveryConfigFileName: &ret.apiConfig.Discovery, + config.RedisConfigFileName: &ret.apiConfig.Redis, } ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap)) ret.ctx = context.WithValue(context.Background(), "version", config.Version) diff --git a/pkg/common/config/config.go b/pkg/common/config/config.go index 53d2db26c..82943eb74 100644 --- a/pkg/common/config/config.go +++ b/pkg/common/config/config.go @@ -16,9 +16,10 @@ var ( type Share struct { OpenIM struct { - ApiURL string `mapstructure:"apiURL"` - Secret string `mapstructure:"secret"` - AdminUserID string `mapstructure:"adminUserID"` + ApiURL string `mapstructure:"apiURL"` + Secret string `mapstructure:"secret"` + AdminUserID string `mapstructure:"adminUserID"` + TokenRefreshInterval int `mapstructure:"tokenRefreshInterval"` } `mapstructure:"openIM"` ChatAdmin []string `mapstructure:"chatAdmin"` ProxyHeader string `mapstructure:"proxyHeader"` @@ -27,6 +28,7 @@ type Share struct { type RpcService struct { Chat string `mapstructure:"chat"` Admin string `mapstructure:"admin"` + Bot string `mapstructure:"bot"` } func (r *RpcService) GetServiceNames() []string { @@ -43,6 +45,13 @@ type API struct { } `mapstructure:"api"` } +type APIBot struct { + Api struct { + ListenIP string `mapstructure:"listenIP"` + Ports []int `mapstructure:"ports"` + } `mapstructure:"api"` +} + type Mongo struct { URI string `mapstructure:"uri"` Address []string `mapstructure:"address"` @@ -146,6 +155,41 @@ type Chat struct { AllowRegister bool `mapstructure:"allowRegister"` } +type Bot struct { + RPC struct { + RegisterIP string `mapstructure:"registerIP"` + ListenIP string `mapstructure:"listenIP"` + Ports []int `mapstructure:"ports"` + } `mapstructure:"rpc"` + Timeout int `mapstructure:"timeout"` +} +type VerifyCode struct { + ValidTime int `mapstructure:"validTime"` + ValidCount int `mapstructure:"validCount"` + UintTime int `mapstructure:"uintTime"` + MaxCount int `mapstructure:"maxCount"` + SuperCode string `mapstructure:"superCode"` + Len int `mapstructure:"len"` + Phone struct { + Use string `mapstructure:"use"` + Ali struct { + Endpoint string `mapstructure:"endpoint"` + AccessKeyID string `mapstructure:"accessKeyId"` + AccessKeySecret string `mapstructure:"accessKeySecret"` + SignName string `mapstructure:"signName"` + VerificationCodeTemplateCode string `mapstructure:"verificationCodeTemplateCode"` + } `mapstructure:"ali"` + } `mapstructure:"phone"` + Mail struct { + Use string `mapstructure:"use"` + Title string `mapstructure:"title"` + SenderMail string `mapstructure:"senderMail"` + SenderAuthorizationCode string `mapstructure:"senderAuthorizationCode"` + SMTPAddr string `mapstructure:"smtpAddr"` + SMTPPort int `mapstructure:"smtpPort"` + } `mapstructure:"mail"` +} + type Admin struct { RPC struct { RegisterIP string `mapstructure:"registerIP"` diff --git a/pkg/common/config/env.go b/pkg/common/config/env.go index aa3170cce..33f0d0768 100644 --- a/pkg/common/config/env.go +++ b/pkg/common/config/env.go @@ -12,8 +12,10 @@ var ( LogConfigFileName = "log.yml" ChatAPIAdminCfgFileName = "chat-api-admin.yml" ChatAPIChatCfgFileName = "chat-api-chat.yml" + ChatAPIBotCfgFileName = "chat-api-bot.yml" ChatRPCAdminCfgFileName = "chat-rpc-admin.yml" ChatRPCChatCfgFileName = "chat-rpc-chat.yml" + ChatRPCBotCfgFileName = "chat-rpc-bot.yml" ) var EnvPrefixMap map[string]string diff --git a/pkg/common/constant/user_id.go b/pkg/common/constant/user_id.go new file mode 100644 index 000000000..5cc00da8a --- /dev/null +++ b/pkg/common/constant/user_id.go @@ -0,0 +1,5 @@ +package constant + +const ( + AgentUserIDPrefix = "bot_" +) diff --git a/pkg/common/convert/agent.go b/pkg/common/convert/agent.go new file mode 100644 index 000000000..15eb49b57 --- /dev/null +++ b/pkg/common/convert/agent.go @@ -0,0 +1,41 @@ +package convert + +import ( + "time" + + "github.com/openimsdk/chat/pkg/common/db/table/bot" + pbbot "github.com/openimsdk/chat/pkg/protocol/bot" + "github.com/openimsdk/tools/utils/datautil" +) + +func DB2PBAgent(a *bot.Agent) *pbbot.Agent { + return &pbbot.Agent{ + UserID: a.UserID, + Nickname: a.NickName, + FaceURL: a.FaceURL, + Url: a.Url, + Key: a.Key, + Identity: a.Identity, + Model: a.Model, + Prompts: a.Prompts, + CreateTime: a.CreateTime.UnixMilli(), + } +} + +func PB2DBAgent(a *pbbot.Agent) *bot.Agent { + return &bot.Agent{ + UserID: a.UserID, + NickName: a.Nickname, + FaceURL: a.FaceURL, + Key: a.Key, + Url: a.Url, + Identity: a.Identity, + Model: a.Model, + Prompts: a.Prompts, + CreateTime: time.UnixMilli(a.CreateTime), + } +} + +func BatchDB2PBAgent(a []*bot.Agent) []*pbbot.Agent { + return datautil.Batch(DB2PBAgent, a) +} diff --git a/pkg/common/db/cache/imtoken.go b/pkg/common/db/cache/imtoken.go new file mode 100644 index 000000000..3d038d009 --- /dev/null +++ b/pkg/common/db/cache/imtoken.go @@ -0,0 +1,50 @@ +package cache + +import ( + "context" + "time" + + "github.com/openimsdk/tools/errs" + "github.com/redis/go-redis/v9" +) + +const ( + chatPrefix = "CHAT:" + imToken = chatPrefix + "IM_TOKEN:" +) + +func getIMTokenKey(userID string) string { + return imToken + userID +} + +type IMTokenInterface interface { + GetToken(ctx context.Context, userID string) (string, error) + SetToken(ctx context.Context, userID, token string) error +} + +type imTokenCacheRedis struct { + rdb redis.UniversalClient + expire time.Duration +} + +func NewIMTokenInterface(rdb redis.UniversalClient, expire int) IMTokenInterface { + return &imTokenCacheRedis{rdb: rdb, expire: time.Duration(expire) * time.Minute} +} + +func (i *imTokenCacheRedis) GetToken(ctx context.Context, userID string) (string, error) { + key := getIMTokenKey(userID) + token, err := i.rdb.Get(ctx, key).Result() + if err != nil { + return "", errs.Wrap(err) + } + return token, nil +} + +func (i *imTokenCacheRedis) SetToken(ctx context.Context, userID, token string) error { + key := getIMTokenKey(userID) + err := i.rdb.Set(ctx, key, token, i.expire).Err() + if err != nil { + return errs.Wrap(err) + } + return nil +} diff --git a/pkg/common/db/cache/token.go b/pkg/common/db/cache/token.go index 3ad6b6ca6..52458143a 100644 --- a/pkg/common/db/cache/token.go +++ b/pkg/common/db/cache/token.go @@ -16,11 +16,10 @@ package cache import ( "context" - "github.com/openimsdk/chat/pkg/common/tokenverify" - "github.com/openimsdk/tools/utils/stringutil" - "sort" "time" + "github.com/openimsdk/tools/utils/stringutil" + "github.com/openimsdk/tools/errs" "github.com/redis/go-redis/v9" ) diff --git a/pkg/common/db/database/bot.go b/pkg/common/db/database/bot.go new file mode 100644 index 000000000..6db664b41 --- /dev/null +++ b/pkg/common/db/database/bot.go @@ -0,0 +1,77 @@ +package database + +import ( + "context" + + "github.com/openimsdk/chat/pkg/common/db/model/bot" + tablebot "github.com/openimsdk/chat/pkg/common/db/table/bot" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + "github.com/openimsdk/tools/db/tx" +) + +type BotDatabase interface { + CreateAgent(ctx context.Context, jobs ...*tablebot.Agent) error + TakeAgent(ctx context.Context, userID string) (*tablebot.Agent, error) + FindAgents(ctx context.Context, userIDs []string) ([]*tablebot.Agent, error) + UpdateAgent(ctx context.Context, userID string, data map[string]any) error + DeleteAgents(ctx context.Context, userIDs []string) error + PageAgents(ctx context.Context, userIDs []string, pagination pagination.Pagination) (int64, []*tablebot.Agent, error) + + TakeConversationRespID(ctx context.Context, convID, agentID string) (*tablebot.ConversationRespID, error) + UpdateConversationRespID(ctx context.Context, convID, agentID string, data map[string]any) error +} + +type botDatabase struct { + tx tx.Tx + agent tablebot.AgentInterface + convRespID tablebot.ConversationRespIDInterface +} + +func NewBotDatabase(cli *mongoutil.Client) (BotDatabase, error) { + agent, err := bot.NewAgent(cli.GetDB()) + if err != nil { + return nil, err + } + convRespID, err := bot.NewConversationRespID(cli.GetDB()) + if err != nil { + return nil, err + } + return &botDatabase{ + tx: cli.GetTx(), + agent: agent, + convRespID: convRespID, + }, nil +} + +func (a *botDatabase) CreateAgent(ctx context.Context, agents ...*tablebot.Agent) error { + return a.agent.Create(ctx, agents...) +} + +func (a *botDatabase) TakeAgent(ctx context.Context, userID string) (*tablebot.Agent, error) { + return a.agent.Take(ctx, userID) +} + +func (a *botDatabase) FindAgents(ctx context.Context, userIDs []string) ([]*tablebot.Agent, error) { + return a.agent.Find(ctx, userIDs) +} + +func (a *botDatabase) UpdateAgent(ctx context.Context, userID string, data map[string]any) error { + return a.agent.Update(ctx, userID, data) +} + +func (a *botDatabase) DeleteAgents(ctx context.Context, userIDs []string) error { + return a.agent.Delete(ctx, userIDs) +} + +func (a *botDatabase) PageAgents(ctx context.Context, userIDs []string, pagination pagination.Pagination) (int64, []*tablebot.Agent, error) { + return a.agent.Page(ctx, userIDs, pagination) +} + +func (a *botDatabase) UpdateConversationRespID(ctx context.Context, convID, agentID string, data map[string]any) error { + return a.convRespID.Update(ctx, convID, agentID, data) +} + +func (a *botDatabase) TakeConversationRespID(ctx context.Context, convID, agentID string) (*tablebot.ConversationRespID, error) { + return a.convRespID.Take(ctx, convID, agentID) +} diff --git a/pkg/common/db/database/imtoken.go b/pkg/common/db/database/imtoken.go new file mode 100644 index 000000000..959d3207c --- /dev/null +++ b/pkg/common/db/database/imtoken.go @@ -0,0 +1,31 @@ +package database + +import ( + "context" + + "github.com/openimsdk/chat/pkg/common/db/cache" + "github.com/redis/go-redis/v9" +) + +type IMTokenDatabase interface { + GetIMToken(ctx context.Context, userID string) (string, error) + SetIMToken(ctx context.Context, userID, token string) error +} + +type imTokenDatabase struct { + db cache.IMTokenInterface +} + +func NewIMTokenDatabase(rdb redis.UniversalClient, expire int) IMTokenDatabase { + return &imTokenDatabase{ + db: cache.NewIMTokenInterface(rdb, expire), + } +} + +func (i *imTokenDatabase) GetIMToken(ctx context.Context, userID string) (string, error) { + return i.db.GetToken(ctx, userID) +} + +func (i *imTokenDatabase) SetIMToken(ctx context.Context, userID, token string) error { + return i.db.SetToken(ctx, userID, token) +} diff --git a/pkg/common/db/model/bot/agent.go b/pkg/common/db/model/bot/agent.go new file mode 100644 index 000000000..526aed07c --- /dev/null +++ b/pkg/common/db/model/bot/agent.go @@ -0,0 +1,65 @@ +package bot + +import ( + "context" + + "github.com/openimsdk/chat/pkg/common/db/table/bot" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/db/pagination" + "github.com/openimsdk/tools/errs" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +func NewAgent(db *mongo.Database) (bot.AgentInterface, error) { + coll := db.Collection("agent") + _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ + Keys: bson.D{ + {Key: "user_id", Value: 1}, + }, + Options: options.Index().SetUnique(true), + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &Agent{coll: coll}, nil +} + +type Agent struct { + coll *mongo.Collection +} + +func (o *Agent) Create(ctx context.Context, elems ...*bot.Agent) error { + return mongoutil.InsertMany(ctx, o.coll, elems) +} + +func (o *Agent) Take(ctx context.Context, userId string) (*bot.Agent, error) { + return mongoutil.FindOne[*bot.Agent](ctx, o.coll, bson.M{"user_id": userId}) +} + +func (o *Agent) Find(ctx context.Context, userIDs []string) ([]*bot.Agent, error) { + return mongoutil.Find[*bot.Agent](ctx, o.coll, bson.M{"user_id": bson.M{"$in": userIDs}}) +} + +func (o *Agent) Update(ctx context.Context, userID string, data map[string]any) error { + if len(data) == 0 { + return nil + } + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"user_id": userID}, bson.M{"$set": data}, false) +} + +func (o *Agent) Delete(ctx context.Context, userIDs []string) error { + if len(userIDs) == 0 { + return nil + } + return mongoutil.DeleteMany(ctx, o.coll, bson.M{"user_id": bson.M{"$in": userIDs}}) +} + +func (o *Agent) Page(ctx context.Context, userIDs []string, pagination pagination.Pagination) (int64, []*bot.Agent, error) { + filter := bson.M{} + if len(userIDs) > 0 { + filter["user_id"] = bson.M{"$in": userIDs} + } + return mongoutil.FindPage[*bot.Agent](ctx, o.coll, filter, pagination) +} diff --git a/pkg/common/db/model/bot/conversation_resp_id.go b/pkg/common/db/model/bot/conversation_resp_id.go new file mode 100644 index 000000000..9ec5b2a86 --- /dev/null +++ b/pkg/common/db/model/bot/conversation_resp_id.go @@ -0,0 +1,50 @@ +package bot + +import ( + "context" + + "github.com/openimsdk/chat/pkg/common/db/table/bot" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/errs" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +func NewConversationRespID(db *mongo.Database) (bot.ConversationRespIDInterface, error) { + coll := db.Collection("conversation_resp_id") + _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ + Keys: bson.D{ + {Key: "conversation_id", Value: 1}, + {Key: "agent_id", Value: 1}, + }, + Options: options.Index().SetUnique(true), + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &ConversationRespID{coll: coll}, nil +} + +type ConversationRespID struct { + coll *mongo.Collection +} + +func (o *ConversationRespID) Create(ctx context.Context, elems ...*bot.ConversationRespID) error { + return mongoutil.InsertMany(ctx, o.coll, elems) +} + +func (o *ConversationRespID) Take(ctx context.Context, convID, agentID string) (*bot.ConversationRespID, error) { + return mongoutil.FindOne[*bot.ConversationRespID](ctx, o.coll, bson.M{"conversation_id": convID, "agent_id": agentID}) +} + +func (o *ConversationRespID) Update(ctx context.Context, convID, agentID string, data map[string]any) error { + if len(data) == 0 { + return nil + } + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"conv_id": convID, "agent_id": agentID}, bson.M{"$set": data}, false, options.Update().SetUpsert(true)) +} + +func (o *ConversationRespID) Delete(ctx context.Context, convID, agentID string) error { + return mongoutil.DeleteMany(ctx, o.coll, bson.M{"conv_id": convID, "agent_id": agentID}) +} diff --git a/pkg/common/db/table/bot/agent.go b/pkg/common/db/table/bot/agent.go new file mode 100644 index 000000000..a78dd3046 --- /dev/null +++ b/pkg/common/db/table/bot/agent.go @@ -0,0 +1,33 @@ +package bot + +import ( + "context" + "time" + + "github.com/openimsdk/tools/db/pagination" +) + +type Agent struct { + UserID string `bson:"user_id"` + NickName string `bson:"nick_name"` + FaceURL string `bson:"face_url"` + Key string `bson:"key"` + Url string `bson:"url"` + Identity string `bson:"identity"` + Model string `bson:"model"` + Prompts string `bson:"prompts"` + CreateTime time.Time `bson:"create_time"` +} + +func (Agent) TableName() string { + return "agent" +} + +type AgentInterface interface { + Create(ctx context.Context, elems ...*Agent) error + Take(ctx context.Context, userID string) (*Agent, error) + Find(ctx context.Context, userIDs []string) ([]*Agent, error) + Update(ctx context.Context, userID string, data map[string]any) error + Delete(ctx context.Context, userIDs []string) error + Page(ctx context.Context, userIDs []string, pagination pagination.Pagination) (int64, []*Agent, error) +} diff --git a/pkg/common/db/table/bot/conversation_resp_id.go b/pkg/common/db/table/bot/conversation_resp_id.go new file mode 100644 index 000000000..ada503e94 --- /dev/null +++ b/pkg/common/db/table/bot/conversation_resp_id.go @@ -0,0 +1,22 @@ +package bot + +import ( + "context" +) + +type ConversationRespID struct { + ConversationID string `bson:"conversation_id"` + AgentID string `bson:"agent_id"` + PreviousResponseID string `bson:"previous_response_id"` +} + +func (ConversationRespID) TableName() string { + return "conversation_resp_id" +} + +type ConversationRespIDInterface interface { + Create(ctx context.Context, elems ...*ConversationRespID) error + Take(ctx context.Context, convID, agentID string) (*ConversationRespID, error) + Update(ctx context.Context, convID, agentID string, data map[string]any) error + Delete(ctx context.Context, convID, agentID string) error +} diff --git a/pkg/common/imapi/api.go b/pkg/common/imapi/api.go index 60891be0f..0e9c4bdb8 100644 --- a/pkg/common/imapi/api.go +++ b/pkg/common/imapi/api.go @@ -23,15 +23,24 @@ import ( // im caller. var ( - importFriend = NewApiCaller[relation.ImportFriendReq, relation.ImportFriendResp]("/friend/import_friend") - getAdminToken = NewApiCaller[auth.GetAdminTokenReq, auth.GetAdminTokenResp]("/auth/get_admin_token") - getuserToken = NewApiCaller[auth.GetUserTokenReq, auth.GetUserTokenResp]("/auth/get_user_token") - inviteToGroup = NewApiCaller[group.InviteUserToGroupReq, group.InviteUserToGroupResp]("/group/invite_user_to_group") - updateUserInfo = NewApiCaller[user.UpdateUserInfoReq, user.UpdateUserInfoResp]("/user/update_user_info") - registerUser = NewApiCaller[user.UserRegisterReq, user.UserRegisterResp]("/user/user_register") - forceOffLine = NewApiCaller[auth.ForceLogoutReq, auth.ForceLogoutResp]("/auth/force_logout") - getGroupsInfo = NewApiCaller[group.GetGroupsInfoReq, group.GetGroupsInfoResp]("/group/get_groups_info") + getAdminToken = NewApiCaller[auth.GetAdminTokenReq, auth.GetAdminTokenResp]("/auth/get_admin_token") + getuserToken = NewApiCaller[auth.GetUserTokenReq, auth.GetUserTokenResp]("/auth/get_user_token") + forceOffLine = NewApiCaller[auth.ForceLogoutReq, auth.ForceLogoutResp]("/auth/force_logout") + + updateUserInfo = NewApiCaller[user.UpdateUserInfoReq, user.UpdateUserInfoResp]("/user/update_user_info") + registerUser = NewApiCaller[user.UserRegisterReq, user.UserRegisterResp]("/user/user_register") + getUserInfo = NewApiCaller[user.GetDesignateUsersReq, user.GetDesignateUsersResp]("/user/get_users_info") + accountCheck = NewApiCaller[user.AccountCheckReq, user.AccountCheckResp]("/user/account_check") + addNotificationAccount = NewApiCaller[user.AddNotificationAccountReq, user.AddNotificationAccountResp]("/user/add_notification_account") + updateNotificationAccount = NewApiCaller[user.UpdateNotificationAccountInfoReq, user.UpdateNotificationAccountInfoResp]("/user/update_notification_account") + + getGroupsInfo = NewApiCaller[group.GetGroupsInfoReq, group.GetGroupsInfoResp]("/group/get_groups_info") + inviteToGroup = NewApiCaller[group.InviteUserToGroupReq, group.InviteUserToGroupResp]("/group/invite_user_to_group") + registerUserCount = NewApiCaller[user.UserRegisterCountReq, user.UserRegisterCountResp]("/statistics/user/register") - friendUserIDs = NewApiCaller[relation.GetFriendIDsReq, relation.GetFriendIDsResp]("/friend/get_friend_id") - accountCheck = NewApiCaller[user.AccountCheckReq, user.AccountCheckResp]("/user/account_check") + + friendUserIDs = NewApiCaller[relation.GetFriendIDsReq, relation.GetFriendIDsResp]("/friend/get_friend_id") + importFriend = NewApiCaller[relation.ImportFriendReq, relation.ImportFriendResp]("/friend/import_friend") + + sendSimpleMsg = NewApiCaller[SendSingleMsgReq, SendSingleMsgResp]("/msg/send_simple_msg") ) diff --git a/pkg/common/imapi/call.go b/pkg/common/imapi/call.go index 2b5646e3c..968262160 100644 --- a/pkg/common/imapi/call.go +++ b/pkg/common/imapi/call.go @@ -20,6 +20,7 @@ import ( "encoding/json" "io" "net/http" + "net/url" "time" "github.com/openimsdk/chat/pkg/common/constant" @@ -42,6 +43,7 @@ var client = &http.Client{ type ApiCaller[Req, Resp any] interface { Call(ctx context.Context, apiPrefix string, req *Req) (*Resp, error) + CallWithQuery(ctx context.Context, apiPrefix string, req *Req, queryParams map[string]string) (*Resp, error) } func NewApiCaller[Req, Resp any](api string) ApiCaller[Req, Resp] { @@ -58,7 +60,7 @@ func (a caller[Req, Resp]) Call(ctx context.Context, apiPrefix string, req *Req) start := time.Now() resp, err := a.call(ctx, apiPrefix, req) if err != nil { - log.ZError(ctx, "api caller failed", err, "api", a.api, "duration", time.Since(start), "req", req) + log.ZError(ctx, "api caller failed", err, "api", a.api, "duration", time.Since(start), "req", req, "resp", resp) return nil, err } log.ZInfo(ctx, "api caller success resp", "api", a.api, "duration", time.Since(start), "req", req, "resp", resp) @@ -98,3 +100,61 @@ func (a caller[Req, Resp]) call(ctx context.Context, apiPrefix string, req *Req) } return resp.Data, nil } + +func (a caller[Req, Resp]) CallWithQuery(ctx context.Context, apiPrefix string, req *Req, queryParams map[string]string) (*Resp, error) { + start := time.Now() + resp, err := a.callWithQuery(ctx, apiPrefix, req, queryParams) + if err != nil { + log.ZError(ctx, "api caller failed", err, "api", a.api, "duration", time.Since(start), "req", req, "resp", resp) + return nil, err + } + log.ZInfo(ctx, "api caller success resp", "api", a.api, "duration", time.Since(start), "req", req, "resp", resp) + return resp, nil +} + +func (a caller[Req, Resp]) callWithQuery(ctx context.Context, apiPrefix string, req *Req, queryParams map[string]string) (*Resp, error) { + fullURL := apiPrefix + a.api + parsedURL, err := url.Parse(fullURL) + if err != nil { + return nil, errs.WrapMsg(err, "failed to parse URL", fullURL) + } + + query := parsedURL.Query() + + for key, value := range queryParams { + query.Set(key, value) + } + + parsedURL.RawQuery = query.Encode() + fullURL = parsedURL.String() + reqBody, err := json.Marshal(req) + if err != nil { + return nil, err + } + request, err := http.NewRequestWithContext(ctx, http.MethodPost, fullURL, bytes.NewReader(reqBody)) + if err != nil { + return nil, err + } + operationID := utils.ToString(ctx.Value(constantpb.OperationID)) + request.Header.Set(constantpb.OperationID, operationID) + if token, _ := ctx.Value(constant.CtxApiToken).(string); token != "" { + request.Header.Set(constantpb.Token, token) + } + response, err := client.Do(request) + if err != nil { + return nil, err + } + defer response.Body.Close() + data, err := io.ReadAll(response.Body) + if err != nil { + return nil, errs.WrapMsg(err, "read http response body", "fullUrl", fullURL, "code", response.StatusCode) + } + var resp baseApiResponse[Resp] + if err := json.Unmarshal(data, &resp); err != nil { + return nil, errs.WrapMsg(err, string(data)) + } + if resp.ErrCode != 0 { + return nil, errs.NewCodeError(resp.ErrCode, resp.ErrMsg).WithDetail(resp.ErrDlt).Wrap() + } + return resp.Data, nil +} diff --git a/pkg/common/imapi/caller.go b/pkg/common/imapi/caller.go index 3ebee9213..a2fdaa68b 100644 --- a/pkg/common/imapi/caller.go +++ b/pkg/common/imapi/caller.go @@ -2,14 +2,19 @@ package imapi import ( "context" - "github.com/openimsdk/tools/log" + "errors" "sync" "time" + "github.com/openimsdk/chat/pkg/botstruct" + "github.com/openimsdk/chat/pkg/common/db/database" + "github.com/openimsdk/tools/errs" + "github.com/openimsdk/tools/log" + "github.com/redis/go-redis/v9" + "github.com/openimsdk/chat/pkg/eerrs" "github.com/openimsdk/protocol/auth" "github.com/openimsdk/protocol/constant" - constantpb "github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/group" "github.com/openimsdk/protocol/relation" "github.com/openimsdk/protocol/sdkws" @@ -21,14 +26,22 @@ type CallerInterface interface { ImportFriend(ctx context.Context, ownerUserID string, friendUserID []string) error GetUserToken(ctx context.Context, userID string, platform int32) (string, error) GetAdminTokenCache(ctx context.Context, userID string) (string, error) + GetAdminTokenServer(ctx context.Context, userID string) (string, error) InviteToGroup(ctx context.Context, userID string, groupIDs []string) error + UpdateUserInfo(ctx context.Context, userID string, nickName string, faceURL string) error + GetUserInfo(ctx context.Context, userID string) (*sdkws.UserInfo, error) + GetUsersInfo(ctx context.Context, userIDs []string) ([]*sdkws.UserInfo, error) + AddNotificationAccount(ctx context.Context, req *user.AddNotificationAccountReq) error + UpdateNotificationAccount(ctx context.Context, req *user.UpdateNotificationAccountInfoReq) error + ForceOffLine(ctx context.Context, userID string) error RegisterUser(ctx context.Context, users []*sdkws.UserInfo) error FindGroupInfo(ctx context.Context, groupIDs []string) ([]*sdkws.GroupInfo, error) UserRegisterCount(ctx context.Context, start int64, end int64) (map[string]int64, int64, error) FriendUserIDs(ctx context.Context, userID string) ([]string, error) AccountCheckSingle(ctx context.Context, userID string) (bool, error) + SendSimpleMsg(ctx context.Context, req *SendSingleMsgReq, key string) error } type authToken struct { @@ -42,15 +55,18 @@ type Caller struct { defaultIMUserID string tokenCache map[string]*authToken lock sync.RWMutex + tokenDB database.IMTokenDatabase } -func New(imApi string, imSecret string, defaultIMUserID string) CallerInterface { +func New(imApi string, imSecret string, defaultIMUserID string, rdb redis.UniversalClient, refreshInterval int) CallerInterface { + tokenDB := database.NewIMTokenDatabase(rdb, refreshInterval) return &Caller{ imApi: imApi, imSecret: imSecret, defaultIMUserID: defaultIMUserID, tokenCache: make(map[string]*authToken), lock: sync.RWMutex{}, + tokenDB: tokenDB, } } @@ -77,21 +93,31 @@ func (c *Caller) GetAdminTokenCache(ctx context.Context, userID string) (string, c.lock.Lock() t, ok = c.tokenCache[userID] if !ok || t.timeout.Before(time.Now()) { - token, err := c.getAdminTokenServer(ctx, userID) - if err != nil { - log.ZError(ctx, "get im admin token", err, "userID", userID) + token, err := c.tokenDB.GetIMToken(ctx, userID) + if err != nil && !errors.Is(err, redis.Nil) { return "", err + } else if errors.Is(err, redis.Nil) { + // no token in redis cache + token, err = c.GetAdminTokenServer(ctx, userID) + if err != nil { + log.ZError(ctx, "get im admin token from server", err, "userID", userID) + return "", err + } + t = &authToken{token: token, timeout: time.Now().Add(time.Minute * 4)} + c.tokenCache[userID] = t + } else { + log.ZDebug(ctx, "get im admin token from cache", "userID", userID, "token", token) + t = &authToken{token: token, timeout: time.Now().Add(time.Minute * 4)} + c.tokenCache[userID] = t } - log.ZDebug(ctx, "get im admin token", "userID", userID) - t = &authToken{token: token, timeout: time.Now().Add(time.Minute * 5)} - c.tokenCache[userID] = t + } c.lock.Unlock() } return t.token, nil } -func (c *Caller) getAdminTokenServer(ctx context.Context, userID string) (string, error) { +func (c *Caller) GetAdminTokenServer(ctx context.Context, userID string) (string, error) { resp, err := getAdminToken.Call(ctx, c.imApi, &auth.GetAdminTokenReq{ Secret: c.imSecret, UserID: userID, @@ -99,6 +125,11 @@ func (c *Caller) getAdminTokenServer(ctx context.Context, userID string) (string if err != nil { return "", err } + log.ZDebug(ctx, "get im admin token from server", "userID", userID, "token", resp.Token) + err = c.tokenDB.SetIMToken(ctx, userID, resp.Token) + if err != nil { + log.ZWarn(ctx, "set im admin token to redis failed", err, "userID", userID) + } return resp.Token, nil } @@ -133,6 +164,27 @@ func (c *Caller) UpdateUserInfo(ctx context.Context, userID string, nickName str return err } +func (c *Caller) GetUserInfo(ctx context.Context, userID string) (*sdkws.UserInfo, error) { + resp, err := c.GetUsersInfo(ctx, []string{userID}) + if err != nil { + return nil, err + } + if len(resp) == 0 { + return nil, errs.ErrRecordNotFound.WrapMsg("record not found") + } + return resp[0], nil +} + +func (c *Caller) GetUsersInfo(ctx context.Context, userIDs []string) ([]*sdkws.UserInfo, error) { + resp, err := getUserInfo.Call(ctx, c.imApi, &user.GetDesignateUsersReq{ + UserIDs: userIDs, + }) + if err != nil { + return nil, err + } + return resp.UsersInfo, nil +} + func (c *Caller) RegisterUser(ctx context.Context, users []*sdkws.UserInfo) error { _, err := registerUser.Call(ctx, c.imApi, &user.UserRegisterReq{ Users: users, @@ -141,7 +193,7 @@ func (c *Caller) RegisterUser(ctx context.Context, users []*sdkws.UserInfo) erro } func (c *Caller) ForceOffLine(ctx context.Context, userID string) error { - for id := range constantpb.PlatformID2Name { + for id := range constant.PlatformID2Name { _, _ = forceOffLine.Call(ctx, c.imApi, &auth.ForceLogoutReq{ PlatformID: int32(id), UserID: userID, @@ -190,3 +242,18 @@ func (c *Caller) AccountCheckSingle(ctx context.Context, userID string) (bool, e } return true, nil } + +func (c *Caller) SendSimpleMsg(ctx context.Context, req *SendSingleMsgReq, key string) error { + _, err := sendSimpleMsg.CallWithQuery(ctx, c.imApi, req, map[string]string{botstruct.Key: key}) + return err +} + +func (c *Caller) AddNotificationAccount(ctx context.Context, req *user.AddNotificationAccountReq) error { + _, err := addNotificationAccount.Call(ctx, c.imApi, req) + return err +} + +func (c *Caller) UpdateNotificationAccount(ctx context.Context, req *user.UpdateNotificationAccountInfoReq) error { + _, err := updateNotificationAccount.Call(ctx, c.imApi, req) + return err +} diff --git a/pkg/common/imapi/model.go b/pkg/common/imapi/model.go new file mode 100644 index 000000000..c2db36be4 --- /dev/null +++ b/pkg/common/imapi/model.go @@ -0,0 +1,13 @@ +package imapi + +import "github.com/openimsdk/protocol/sdkws" + +// SendSingleMsgReq defines the structure for sending a message to multiple recipients. +type SendSingleMsgReq struct { + // groupMsg should appoint sendID + SendID string `json:"sendID"` + Content string `json:"content" binding:"required"` + OfflinePushInfo *sdkws.OfflinePushInfo `json:"offlinePushInfo"` + Ex string `json:"ex"` +} +type SendSingleMsgResp struct{} diff --git a/pkg/common/imwebhook/message.go b/pkg/common/imwebhook/message.go new file mode 100644 index 000000000..f09280a85 --- /dev/null +++ b/pkg/common/imwebhook/message.go @@ -0,0 +1,48 @@ +package imwebhook + +type CommonCallbackReq struct { + SendID string `json:"sendID"` + CallbackCommand string `json:"callbackCommand"` + ServerMsgID string `json:"serverMsgID"` + ClientMsgID string `json:"clientMsgID"` + OperationID string `json:"operationID"` + SenderPlatformID int32 `json:"senderPlatformID"` + SenderNickname string `json:"senderNickname"` + SessionType int32 `json:"sessionType"` + MsgFrom int32 `json:"msgFrom"` + ContentType int32 `json:"contentType"` + Status int32 `json:"status"` + SendTime int64 `json:"sendTime"` + CreateTime int64 `json:"createTime"` + Content string `json:"content"` + Seq uint32 `json:"seq"` + AtUserIDList []string `json:"atUserList"` + SenderFaceURL string `json:"faceURL"` + Ex string `json:"ex"` +} + +type CommonCallbackResp struct { + ActionCode int32 `json:"actionCode"` + ErrCode int32 `json:"errCode"` + ErrMsg string `json:"errMsg"` + ErrDlt string `json:"errDlt"` + NextCode int32 `json:"nextCode"` +} + +type CallbackAfterSendSingleMsgReq struct { + CommonCallbackReq + RecvID string `json:"recvID"` +} + +type CallbackAfterSendSingleMsgResp struct { + CommonCallbackResp +} + +type CallbackAfterSendGroupMsgReq struct { + CommonCallbackReq + GroupID string `json:"groupID"` +} + +type CallbackAfterSendGroupMsgResp struct { + CommonCallbackResp +} diff --git a/pkg/protocol/bot/bot.pb.go b/pkg/protocol/bot/bot.pb.go new file mode 100644 index 000000000..3376342f9 --- /dev/null +++ b/pkg/protocol/bot/bot.pb.go @@ -0,0 +1,829 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.1 +// protoc v5.29.0 +// source: bot/bot.proto + +package bot + +import ( + sdkws "github.com/openimsdk/protocol/sdkws" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Agent struct { + state protoimpl.MessageState `protogen:"open.v1"` + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` + Nickname string `protobuf:"bytes,2,opt,name=nickname,proto3" json:"nickname"` + FaceURL string `protobuf:"bytes,3,opt,name=faceURL,proto3" json:"faceURL"` + Url string `protobuf:"bytes,4,opt,name=url,proto3" json:"url"` + Key string `protobuf:"bytes,5,opt,name=key,proto3" json:"key"` + Identity string `protobuf:"bytes,6,opt,name=identity,proto3" json:"identity"` + Model string `protobuf:"bytes,7,opt,name=model,proto3" json:"model"` + Prompts string `protobuf:"bytes,8,opt,name=prompts,proto3" json:"prompts"` + CreateTime int64 `protobuf:"varint,9,opt,name=createTime,proto3" json:"createTime"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Agent) Reset() { + *x = Agent{} + mi := &file_bot_bot_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Agent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Agent) ProtoMessage() {} + +func (x *Agent) ProtoReflect() protoreflect.Message { + mi := &file_bot_bot_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Agent.ProtoReflect.Descriptor instead. +func (*Agent) Descriptor() ([]byte, []int) { + return file_bot_bot_proto_rawDescGZIP(), []int{0} +} + +func (x *Agent) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *Agent) GetNickname() string { + if x != nil { + return x.Nickname + } + return "" +} + +func (x *Agent) GetFaceURL() string { + if x != nil { + return x.FaceURL + } + return "" +} + +func (x *Agent) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *Agent) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *Agent) GetIdentity() string { + if x != nil { + return x.Identity + } + return "" +} + +func (x *Agent) GetModel() string { + if x != nil { + return x.Model + } + return "" +} + +func (x *Agent) GetPrompts() string { + if x != nil { + return x.Prompts + } + return "" +} + +func (x *Agent) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +type CreateAgentReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Agent *Agent `protobuf:"bytes,1,opt,name=agent,proto3" json:"agent"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateAgentReq) Reset() { + *x = CreateAgentReq{} + mi := &file_bot_bot_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateAgentReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateAgentReq) ProtoMessage() {} + +func (x *CreateAgentReq) ProtoReflect() protoreflect.Message { + mi := &file_bot_bot_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateAgentReq.ProtoReflect.Descriptor instead. +func (*CreateAgentReq) Descriptor() ([]byte, []int) { + return file_bot_bot_proto_rawDescGZIP(), []int{1} +} + +func (x *CreateAgentReq) GetAgent() *Agent { + if x != nil { + return x.Agent + } + return nil +} + +type CreateAgentResp struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateAgentResp) Reset() { + *x = CreateAgentResp{} + mi := &file_bot_bot_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateAgentResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateAgentResp) ProtoMessage() {} + +func (x *CreateAgentResp) ProtoReflect() protoreflect.Message { + mi := &file_bot_bot_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateAgentResp.ProtoReflect.Descriptor instead. +func (*CreateAgentResp) Descriptor() ([]byte, []int) { + return file_bot_bot_proto_rawDescGZIP(), []int{2} +} + +type UpdateAgentReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + UserID string `protobuf:"bytes,1,opt,name=userID,proto3" json:"userID"` + Nickname *string `protobuf:"bytes,2,opt,name=nickname,proto3,oneof" json:"nickname"` + FaceURL *string `protobuf:"bytes,3,opt,name=faceURL,proto3,oneof" json:"faceURL"` + Url *string `protobuf:"bytes,4,opt,name=url,proto3,oneof" json:"url"` + Key *string `protobuf:"bytes,5,opt,name=key,proto3,oneof" json:"key"` + Identity *string `protobuf:"bytes,6,opt,name=identity,proto3,oneof" json:"identity"` + Model *string `protobuf:"bytes,7,opt,name=model,proto3,oneof" json:"model"` + Prompts *string `protobuf:"bytes,8,opt,name=prompts,proto3,oneof" json:"prompts"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateAgentReq) Reset() { + *x = UpdateAgentReq{} + mi := &file_bot_bot_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateAgentReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateAgentReq) ProtoMessage() {} + +func (x *UpdateAgentReq) ProtoReflect() protoreflect.Message { + mi := &file_bot_bot_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateAgentReq.ProtoReflect.Descriptor instead. +func (*UpdateAgentReq) Descriptor() ([]byte, []int) { + return file_bot_bot_proto_rawDescGZIP(), []int{3} +} + +func (x *UpdateAgentReq) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +func (x *UpdateAgentReq) GetNickname() string { + if x != nil && x.Nickname != nil { + return *x.Nickname + } + return "" +} + +func (x *UpdateAgentReq) GetFaceURL() string { + if x != nil && x.FaceURL != nil { + return *x.FaceURL + } + return "" +} + +func (x *UpdateAgentReq) GetUrl() string { + if x != nil && x.Url != nil { + return *x.Url + } + return "" +} + +func (x *UpdateAgentReq) GetKey() string { + if x != nil && x.Key != nil { + return *x.Key + } + return "" +} + +func (x *UpdateAgentReq) GetIdentity() string { + if x != nil && x.Identity != nil { + return *x.Identity + } + return "" +} + +func (x *UpdateAgentReq) GetModel() string { + if x != nil && x.Model != nil { + return *x.Model + } + return "" +} + +func (x *UpdateAgentReq) GetPrompts() string { + if x != nil && x.Prompts != nil { + return *x.Prompts + } + return "" +} + +type UpdateAgentResp struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateAgentResp) Reset() { + *x = UpdateAgentResp{} + mi := &file_bot_bot_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateAgentResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateAgentResp) ProtoMessage() {} + +func (x *UpdateAgentResp) ProtoReflect() protoreflect.Message { + mi := &file_bot_bot_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateAgentResp.ProtoReflect.Descriptor instead. +func (*UpdateAgentResp) Descriptor() ([]byte, []int) { + return file_bot_bot_proto_rawDescGZIP(), []int{4} +} + +type PageFindAgentReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Pagination *sdkws.RequestPagination `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination"` + UserIDs []string `protobuf:"bytes,2,rep,name=userIDs,proto3" json:"userIDs"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PageFindAgentReq) Reset() { + *x = PageFindAgentReq{} + mi := &file_bot_bot_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PageFindAgentReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PageFindAgentReq) ProtoMessage() {} + +func (x *PageFindAgentReq) ProtoReflect() protoreflect.Message { + mi := &file_bot_bot_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PageFindAgentReq.ProtoReflect.Descriptor instead. +func (*PageFindAgentReq) Descriptor() ([]byte, []int) { + return file_bot_bot_proto_rawDescGZIP(), []int{5} +} + +func (x *PageFindAgentReq) GetPagination() *sdkws.RequestPagination { + if x != nil { + return x.Pagination + } + return nil +} + +func (x *PageFindAgentReq) GetUserIDs() []string { + if x != nil { + return x.UserIDs + } + return nil +} + +type PageFindAgentResp struct { + state protoimpl.MessageState `protogen:"open.v1"` + Total int64 `protobuf:"varint,1,opt,name=total,proto3" json:"total"` + Agents []*Agent `protobuf:"bytes,2,rep,name=agents,proto3" json:"agents"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PageFindAgentResp) Reset() { + *x = PageFindAgentResp{} + mi := &file_bot_bot_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PageFindAgentResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PageFindAgentResp) ProtoMessage() {} + +func (x *PageFindAgentResp) ProtoReflect() protoreflect.Message { + mi := &file_bot_bot_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PageFindAgentResp.ProtoReflect.Descriptor instead. +func (*PageFindAgentResp) Descriptor() ([]byte, []int) { + return file_bot_bot_proto_rawDescGZIP(), []int{6} +} + +func (x *PageFindAgentResp) GetTotal() int64 { + if x != nil { + return x.Total + } + return 0 +} + +func (x *PageFindAgentResp) GetAgents() []*Agent { + if x != nil { + return x.Agents + } + return nil +} + +type DeleteAgentReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + UserIDs []string `protobuf:"bytes,1,rep,name=userIDs,proto3" json:"userIDs"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteAgentReq) Reset() { + *x = DeleteAgentReq{} + mi := &file_bot_bot_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteAgentReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteAgentReq) ProtoMessage() {} + +func (x *DeleteAgentReq) ProtoReflect() protoreflect.Message { + mi := &file_bot_bot_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteAgentReq.ProtoReflect.Descriptor instead. +func (*DeleteAgentReq) Descriptor() ([]byte, []int) { + return file_bot_bot_proto_rawDescGZIP(), []int{7} +} + +func (x *DeleteAgentReq) GetUserIDs() []string { + if x != nil { + return x.UserIDs + } + return nil +} + +type DeleteAgentResp struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteAgentResp) Reset() { + *x = DeleteAgentResp{} + mi := &file_bot_bot_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteAgentResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteAgentResp) ProtoMessage() {} + +func (x *DeleteAgentResp) ProtoReflect() protoreflect.Message { + mi := &file_bot_bot_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteAgentResp.ProtoReflect.Descriptor instead. +func (*DeleteAgentResp) Descriptor() ([]byte, []int) { + return file_bot_bot_proto_rawDescGZIP(), []int{8} +} + +type SendBotMessageReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + AgentID string `protobuf:"bytes,1,opt,name=agentID,proto3" json:"agentID"` + ConversationID string `protobuf:"bytes,2,opt,name=conversationID,proto3" json:"conversationID"` + ContentType int32 `protobuf:"varint,3,opt,name=contentType,proto3" json:"contentType"` + Content string `protobuf:"bytes,4,opt,name=content,proto3" json:"content"` + Ex string `protobuf:"bytes,5,opt,name=ex,proto3" json:"ex"` + Key string `protobuf:"bytes,6,opt,name=key,proto3" json:"key"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SendBotMessageReq) Reset() { + *x = SendBotMessageReq{} + mi := &file_bot_bot_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SendBotMessageReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SendBotMessageReq) ProtoMessage() {} + +func (x *SendBotMessageReq) ProtoReflect() protoreflect.Message { + mi := &file_bot_bot_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SendBotMessageReq.ProtoReflect.Descriptor instead. +func (*SendBotMessageReq) Descriptor() ([]byte, []int) { + return file_bot_bot_proto_rawDescGZIP(), []int{9} +} + +func (x *SendBotMessageReq) GetAgentID() string { + if x != nil { + return x.AgentID + } + return "" +} + +func (x *SendBotMessageReq) GetConversationID() string { + if x != nil { + return x.ConversationID + } + return "" +} + +func (x *SendBotMessageReq) GetContentType() int32 { + if x != nil { + return x.ContentType + } + return 0 +} + +func (x *SendBotMessageReq) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *SendBotMessageReq) GetEx() string { + if x != nil { + return x.Ex + } + return "" +} + +func (x *SendBotMessageReq) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +type SendBotMessageResp struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SendBotMessageResp) Reset() { + *x = SendBotMessageResp{} + mi := &file_bot_bot_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SendBotMessageResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SendBotMessageResp) ProtoMessage() {} + +func (x *SendBotMessageResp) ProtoReflect() protoreflect.Message { + mi := &file_bot_bot_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SendBotMessageResp.ProtoReflect.Descriptor instead. +func (*SendBotMessageResp) Descriptor() ([]byte, []int) { + return file_bot_bot_proto_rawDescGZIP(), []int{10} +} + +var File_bot_bot_proto protoreflect.FileDescriptor + +var file_bot_bot_proto_rawDesc = []byte{ + 0x0a, 0x0d, 0x62, 0x6f, 0x74, 0x2f, 0x62, 0x6f, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, + 0x0a, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x62, 0x6f, 0x74, 0x1a, 0x11, 0x73, 0x64, 0x6b, + 0x77, 0x73, 0x2f, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe5, + 0x01, 0x0a, 0x05, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, + 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, + 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, + 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x18, 0x0a, 0x07, + 0x70, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, + 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x54, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x39, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x12, 0x27, 0x0a, 0x05, 0x61, 0x67, 0x65, 0x6e, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x62, 0x6f, 0x74, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x61, 0x67, 0x65, 0x6e, + 0x74, 0x22, 0x11, 0x0a, 0x0f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x22, 0xbd, 0x02, 0x0a, 0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, + 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, + 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, + 0x1f, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x48, 0x00, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, + 0x12, 0x1d, 0x0a, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x48, 0x01, 0x52, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x88, 0x01, 0x01, 0x12, + 0x15, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x03, + 0x75, 0x72, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x15, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x88, 0x01, 0x01, 0x12, 0x1f, 0x0a, + 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x48, + 0x04, 0x52, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x88, 0x01, 0x01, 0x12, 0x19, + 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x48, 0x05, 0x52, + 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07, 0x70, 0x72, 0x6f, + 0x6d, 0x70, 0x74, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x48, 0x06, 0x52, 0x07, 0x70, 0x72, + 0x6f, 0x6d, 0x70, 0x74, 0x73, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x6e, 0x69, 0x63, + 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, + 0x4c, 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x75, 0x72, 0x6c, 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x6b, 0x65, + 0x79, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x42, 0x08, + 0x0a, 0x06, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x70, 0x72, 0x6f, + 0x6d, 0x70, 0x74, 0x73, 0x22, 0x11, 0x0a, 0x0f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67, + 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x22, 0x6d, 0x0a, 0x10, 0x50, 0x61, 0x67, 0x65, 0x46, + 0x69, 0x6e, 0x64, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x12, 0x3f, 0x0a, 0x0a, 0x70, + 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, + 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x75, + 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x22, 0x54, 0x0a, 0x11, 0x50, 0x61, 0x67, 0x65, 0x46, 0x69, + 0x6e, 0x64, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, + 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, + 0x6c, 0x12, 0x29, 0x0a, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x11, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x62, 0x6f, 0x74, 0x2e, 0x41, + 0x67, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x2a, 0x0a, 0x0e, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x12, 0x18, + 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x22, 0x11, 0x0a, 0x0f, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x22, 0xb3, 0x01, 0x0a, 0x11, + 0x53, 0x65, 0x6e, 0x64, 0x42, 0x6f, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, + 0x71, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x12, 0x26, 0x0a, 0x0e, 0x63, + 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x44, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, + 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, + 0x0e, 0x0a, 0x02, 0x65, 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x65, 0x78, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x22, 0x14, 0x0a, 0x12, 0x53, 0x65, 0x6e, 0x64, 0x42, 0x6f, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x32, 0xfc, 0x02, 0x0a, 0x03, 0x62, 0x6f, 0x74, 0x12, + 0x46, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x1a, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x62, 0x6f, 0x74, 0x2e, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x62, 0x6f, 0x74, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x67, + 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x46, 0x0a, 0x0b, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x1a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x62, 0x6f, 0x74, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, + 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x62, 0x6f, 0x74, 0x2e, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x4c, 0x0a, 0x0d, 0x50, 0x61, 0x67, 0x65, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x67, 0x65, 0x6e, 0x74, + 0x12, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x62, 0x6f, 0x74, 0x2e, 0x50, 0x61, + 0x67, 0x65, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1d, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x62, 0x6f, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, + 0x46, 0x69, 0x6e, 0x64, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x46, 0x0a, + 0x0b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x1a, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x62, 0x6f, 0x74, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x62, 0x6f, 0x74, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4f, 0x0a, 0x0e, 0x53, 0x65, 0x6e, 0x64, 0x42, 0x6f, 0x74, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x62, 0x6f, 0x74, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x42, 0x6f, 0x74, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x62, 0x6f, 0x74, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x42, 0x6f, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x73, 0x64, 0x6b, 0x2f, 0x63, + 0x68, 0x61, 0x74, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, + 0x2f, 0x62, 0x6f, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_bot_bot_proto_rawDescOnce sync.Once + file_bot_bot_proto_rawDescData = file_bot_bot_proto_rawDesc +) + +func file_bot_bot_proto_rawDescGZIP() []byte { + file_bot_bot_proto_rawDescOnce.Do(func() { + file_bot_bot_proto_rawDescData = protoimpl.X.CompressGZIP(file_bot_bot_proto_rawDescData) + }) + return file_bot_bot_proto_rawDescData +} + +var file_bot_bot_proto_msgTypes = make([]protoimpl.MessageInfo, 11) +var file_bot_bot_proto_goTypes = []any{ + (*Agent)(nil), // 0: openim.bot.Agent + (*CreateAgentReq)(nil), // 1: openim.bot.CreateAgentReq + (*CreateAgentResp)(nil), // 2: openim.bot.CreateAgentResp + (*UpdateAgentReq)(nil), // 3: openim.bot.UpdateAgentReq + (*UpdateAgentResp)(nil), // 4: openim.bot.UpdateAgentResp + (*PageFindAgentReq)(nil), // 5: openim.bot.PageFindAgentReq + (*PageFindAgentResp)(nil), // 6: openim.bot.PageFindAgentResp + (*DeleteAgentReq)(nil), // 7: openim.bot.DeleteAgentReq + (*DeleteAgentResp)(nil), // 8: openim.bot.DeleteAgentResp + (*SendBotMessageReq)(nil), // 9: openim.bot.SendBotMessageReq + (*SendBotMessageResp)(nil), // 10: openim.bot.SendBotMessageResp + (*sdkws.RequestPagination)(nil), // 11: openim.sdkws.RequestPagination +} +var file_bot_bot_proto_depIdxs = []int32{ + 0, // 0: openim.bot.CreateAgentReq.agent:type_name -> openim.bot.Agent + 11, // 1: openim.bot.PageFindAgentReq.pagination:type_name -> openim.sdkws.RequestPagination + 0, // 2: openim.bot.PageFindAgentResp.agents:type_name -> openim.bot.Agent + 1, // 3: openim.bot.bot.CreateAgent:input_type -> openim.bot.CreateAgentReq + 3, // 4: openim.bot.bot.UpdateAgent:input_type -> openim.bot.UpdateAgentReq + 5, // 5: openim.bot.bot.PageFindAgent:input_type -> openim.bot.PageFindAgentReq + 7, // 6: openim.bot.bot.DeleteAgent:input_type -> openim.bot.DeleteAgentReq + 9, // 7: openim.bot.bot.SendBotMessage:input_type -> openim.bot.SendBotMessageReq + 2, // 8: openim.bot.bot.CreateAgent:output_type -> openim.bot.CreateAgentResp + 4, // 9: openim.bot.bot.UpdateAgent:output_type -> openim.bot.UpdateAgentResp + 6, // 10: openim.bot.bot.PageFindAgent:output_type -> openim.bot.PageFindAgentResp + 8, // 11: openim.bot.bot.DeleteAgent:output_type -> openim.bot.DeleteAgentResp + 10, // 12: openim.bot.bot.SendBotMessage:output_type -> openim.bot.SendBotMessageResp + 8, // [8:13] is the sub-list for method output_type + 3, // [3:8] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_bot_bot_proto_init() } +func file_bot_bot_proto_init() { + if File_bot_bot_proto != nil { + return + } + file_bot_bot_proto_msgTypes[3].OneofWrappers = []any{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_bot_bot_proto_rawDesc, + NumEnums: 0, + NumMessages: 11, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_bot_bot_proto_goTypes, + DependencyIndexes: file_bot_bot_proto_depIdxs, + MessageInfos: file_bot_bot_proto_msgTypes, + }.Build() + File_bot_bot_proto = out.File + file_bot_bot_proto_rawDesc = nil + file_bot_bot_proto_goTypes = nil + file_bot_bot_proto_depIdxs = nil +} diff --git a/pkg/protocol/bot/bot.proto b/pkg/protocol/bot/bot.proto new file mode 100644 index 000000000..6f05d82cc --- /dev/null +++ b/pkg/protocol/bot/bot.proto @@ -0,0 +1,73 @@ +syntax = "proto3"; +package openim.bot; + +import "sdkws/sdkws.proto"; + +option go_package = "github.com/openimsdk/chat/pkg/protocol/bot"; + +message Agent { + string userID = 1; + string nickname = 2; + string faceURL = 3; + string url = 4; + string key = 5; + string identity = 6; + string model = 7; + string prompts = 8; + int64 createTime = 9; +} + +message CreateAgentReq { + Agent agent = 1; +} + +message CreateAgentResp { +} + +message UpdateAgentReq { + string userID = 1; + optional string nickname = 2; + optional string faceURL = 3; + optional string url = 4; + optional string key = 5; + optional string identity = 6; + optional string model = 7; + optional string prompts = 8; +} + +message UpdateAgentResp { +} + +message PageFindAgentReq { + openim.sdkws.RequestPagination pagination = 1; + repeated string userIDs = 2; +} + +message PageFindAgentResp { + int64 total = 1; + repeated Agent agents = 2; +} + +message DeleteAgentReq{ + repeated string userIDs = 1; +} +message DeleteAgentResp{} + +message SendBotMessageReq{ + string agentID = 1; + string conversationID = 2; + int32 contentType = 3; + string content = 4; + string ex = 5; + string key = 6; +} +message SendBotMessageResp{} + +service bot { + rpc CreateAgent(CreateAgentReq) returns (CreateAgentResp); + rpc UpdateAgent(UpdateAgentReq) returns (UpdateAgentResp); + rpc PageFindAgent(PageFindAgentReq) returns (PageFindAgentResp); + rpc DeleteAgent(DeleteAgentReq) returns (DeleteAgentResp); + + rpc SendBotMessage(SendBotMessageReq) returns (SendBotMessageResp); +} diff --git a/pkg/protocol/bot/bot_grpc.pb.go b/pkg/protocol/bot/bot_grpc.pb.go new file mode 100644 index 000000000..98f38ccb3 --- /dev/null +++ b/pkg/protocol/bot/bot_grpc.pb.go @@ -0,0 +1,273 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.29.0 +// source: bot/bot.proto + +package bot + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + Bot_CreateAgent_FullMethodName = "/openim.bot.bot/CreateAgent" + Bot_UpdateAgent_FullMethodName = "/openim.bot.bot/UpdateAgent" + Bot_PageFindAgent_FullMethodName = "/openim.bot.bot/PageFindAgent" + Bot_DeleteAgent_FullMethodName = "/openim.bot.bot/DeleteAgent" + Bot_SendBotMessage_FullMethodName = "/openim.bot.bot/SendBotMessage" +) + +// BotClient is the client API for Bot service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type BotClient interface { + CreateAgent(ctx context.Context, in *CreateAgentReq, opts ...grpc.CallOption) (*CreateAgentResp, error) + UpdateAgent(ctx context.Context, in *UpdateAgentReq, opts ...grpc.CallOption) (*UpdateAgentResp, error) + PageFindAgent(ctx context.Context, in *PageFindAgentReq, opts ...grpc.CallOption) (*PageFindAgentResp, error) + DeleteAgent(ctx context.Context, in *DeleteAgentReq, opts ...grpc.CallOption) (*DeleteAgentResp, error) + SendBotMessage(ctx context.Context, in *SendBotMessageReq, opts ...grpc.CallOption) (*SendBotMessageResp, error) +} + +type botClient struct { + cc grpc.ClientConnInterface +} + +func NewBotClient(cc grpc.ClientConnInterface) BotClient { + return &botClient{cc} +} + +func (c *botClient) CreateAgent(ctx context.Context, in *CreateAgentReq, opts ...grpc.CallOption) (*CreateAgentResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CreateAgentResp) + err := c.cc.Invoke(ctx, Bot_CreateAgent_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *botClient) UpdateAgent(ctx context.Context, in *UpdateAgentReq, opts ...grpc.CallOption) (*UpdateAgentResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateAgentResp) + err := c.cc.Invoke(ctx, Bot_UpdateAgent_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *botClient) PageFindAgent(ctx context.Context, in *PageFindAgentReq, opts ...grpc.CallOption) (*PageFindAgentResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(PageFindAgentResp) + err := c.cc.Invoke(ctx, Bot_PageFindAgent_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *botClient) DeleteAgent(ctx context.Context, in *DeleteAgentReq, opts ...grpc.CallOption) (*DeleteAgentResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteAgentResp) + err := c.cc.Invoke(ctx, Bot_DeleteAgent_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *botClient) SendBotMessage(ctx context.Context, in *SendBotMessageReq, opts ...grpc.CallOption) (*SendBotMessageResp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SendBotMessageResp) + err := c.cc.Invoke(ctx, Bot_SendBotMessage_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// BotServer is the server API for Bot service. +// All implementations must embed UnimplementedBotServer +// for forward compatibility. +type BotServer interface { + CreateAgent(context.Context, *CreateAgentReq) (*CreateAgentResp, error) + UpdateAgent(context.Context, *UpdateAgentReq) (*UpdateAgentResp, error) + PageFindAgent(context.Context, *PageFindAgentReq) (*PageFindAgentResp, error) + DeleteAgent(context.Context, *DeleteAgentReq) (*DeleteAgentResp, error) + SendBotMessage(context.Context, *SendBotMessageReq) (*SendBotMessageResp, error) + mustEmbedUnimplementedBotServer() +} + +// UnimplementedBotServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedBotServer struct{} + +func (UnimplementedBotServer) CreateAgent(context.Context, *CreateAgentReq) (*CreateAgentResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateAgent not implemented") +} +func (UnimplementedBotServer) UpdateAgent(context.Context, *UpdateAgentReq) (*UpdateAgentResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateAgent not implemented") +} +func (UnimplementedBotServer) PageFindAgent(context.Context, *PageFindAgentReq) (*PageFindAgentResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method PageFindAgent not implemented") +} +func (UnimplementedBotServer) DeleteAgent(context.Context, *DeleteAgentReq) (*DeleteAgentResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteAgent not implemented") +} +func (UnimplementedBotServer) SendBotMessage(context.Context, *SendBotMessageReq) (*SendBotMessageResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method SendBotMessage not implemented") +} +func (UnimplementedBotServer) mustEmbedUnimplementedBotServer() {} +func (UnimplementedBotServer) testEmbeddedByValue() {} + +// UnsafeBotServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to BotServer will +// result in compilation errors. +type UnsafeBotServer interface { + mustEmbedUnimplementedBotServer() +} + +func RegisterBotServer(s grpc.ServiceRegistrar, srv BotServer) { + // If the following call pancis, it indicates UnimplementedBotServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&Bot_ServiceDesc, srv) +} + +func _Bot_CreateAgent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateAgentReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BotServer).CreateAgent(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Bot_CreateAgent_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BotServer).CreateAgent(ctx, req.(*CreateAgentReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Bot_UpdateAgent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateAgentReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BotServer).UpdateAgent(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Bot_UpdateAgent_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BotServer).UpdateAgent(ctx, req.(*UpdateAgentReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Bot_PageFindAgent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PageFindAgentReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BotServer).PageFindAgent(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Bot_PageFindAgent_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BotServer).PageFindAgent(ctx, req.(*PageFindAgentReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Bot_DeleteAgent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteAgentReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BotServer).DeleteAgent(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Bot_DeleteAgent_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BotServer).DeleteAgent(ctx, req.(*DeleteAgentReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Bot_SendBotMessage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SendBotMessageReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BotServer).SendBotMessage(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Bot_SendBotMessage_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BotServer).SendBotMessage(ctx, req.(*SendBotMessageReq)) + } + return interceptor(ctx, in, info, handler) +} + +// Bot_ServiceDesc is the grpc.ServiceDesc for Bot service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Bot_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "openim.bot.bot", + HandlerType: (*BotServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "CreateAgent", + Handler: _Bot_CreateAgent_Handler, + }, + { + MethodName: "UpdateAgent", + Handler: _Bot_UpdateAgent_Handler, + }, + { + MethodName: "PageFindAgent", + Handler: _Bot_PageFindAgent_Handler, + }, + { + MethodName: "DeleteAgent", + Handler: _Bot_DeleteAgent_Handler, + }, + { + MethodName: "SendBotMessage", + Handler: _Bot_SendBotMessage_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "bot/bot.proto", +} diff --git a/pkg/protocol/gen.cmd b/pkg/protocol/gen.cmd index b837c1d57..7fb2c433b 100644 --- a/pkg/protocol/gen.cmd +++ b/pkg/protocol/gen.cmd @@ -2,7 +2,7 @@ setlocal rem Define array elements -set "PROTO_NAMES=admin chat common" +set "PROTO_NAMES=admin chat common bot" rem Loop through each element in the array for %%i in (%PROTO_NAMES%) do ( diff --git a/start-config.yml b/start-config.yml index 0d6707834..1fb653bdb 100644 --- a/start-config.yml +++ b/start-config.yml @@ -3,6 +3,8 @@ serviceBinaries: chat-rpc: 1 admin-api: 1 admin-rpc: 1 + bot-api: 1 + bot-rpc: 1 toolBinaries: - check-component - attribute-to-credential diff --git a/tools/check-component/main.go b/tools/check-component/main.go index 00206abbe..2433a9172 100644 --- a/tools/check-component/main.go +++ b/tools/check-component/main.go @@ -50,9 +50,13 @@ func CheckRedis(ctx context.Context, config *config.Redis) error { return redisutil.Check(ctx, config.Build()) } -func CheckOpenIM(ctx context.Context, apiURL, secret, adminUserID string) error { - imAPI := imapi.New(apiURL, secret, adminUserID) - _, err := imAPI.GetAdminTokenCache(mcontext.SetOperationID(ctx, "CheckOpenIM"+idutil.OperationIDGenerator()), adminUserID) +func CheckOpenIM(ctx context.Context, apiURL, secret, adminUserID string, redisConf *config.Redis, interval int) error { + rdb, err := redisutil.NewRedisClient(ctx, redisConf.Build()) + if err != nil { + return err + } + imAPI := imapi.New(apiURL, secret, adminUserID, rdb, interval) + _, err = imAPI.GetAdminTokenServer(mcontext.SetOperationID(ctx, "CheckOpenIM"+idutil.OperationIDGenerator()), adminUserID) return err } @@ -123,7 +127,7 @@ func performChecks(ctx context.Context, mongoConfig *config.Mongo, redisConfig * return CheckRedis(ctx, redisConfig) }, "OpenIM": func(ctx context.Context) error { - return CheckOpenIM(ctx, shareConfig.OpenIM.ApiURL, shareConfig.OpenIM.Secret, shareConfig.OpenIM.AdminUserID) + return CheckOpenIM(ctx, shareConfig.OpenIM.ApiURL, shareConfig.OpenIM.Secret, shareConfig.OpenIM.AdminUserID, redisConfig, shareConfig.OpenIM.TokenRefreshInterval) }, } From 5875beee6f0e5fe19e90d288c68d1b368348ddd3 Mon Sep 17 00:00:00 2001 From: icey-yu <119291641+icey-yu@users.noreply.github.com> Date: Wed, 14 May 2025 18:35:03 +0800 Subject: [PATCH 33/36] fix: data version SetVersion will add record (#656) --- tools/dataversion/data_version.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/dataversion/data_version.go b/tools/dataversion/data_version.go index 8a1bb8396..b7525cbdf 100644 --- a/tools/dataversion/data_version.go +++ b/tools/dataversion/data_version.go @@ -4,12 +4,13 @@ import ( "context" "errors" "fmt" + "strconv" + "time" + "github.com/openimsdk/tools/db/mongoutil" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" - "strconv" - "time" ) const ( @@ -44,7 +45,7 @@ func SetVersion(coll *mongo.Collection, key string, version int) error { ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() option := options.Update().SetUpsert(true) - filter := bson.M{"key": key, "value": strconv.Itoa(version)} + filter := bson.M{"key": key} update := bson.M{"$set": bson.M{"key": key, "value": strconv.Itoa(version)}} return mongoutil.UpdateOne(ctx, coll, filter, update, false, option) } From bf3a4ccac97250b3ba5d8fa0fae9ff3b70096488 Mon Sep 17 00:00:00 2001 From: icey-yu <119291641+icey-yu@users.noreply.github.com> Date: Tue, 6 May 2025 14:46:45 +0800 Subject: [PATCH 34/36] feat: Add version check in admin login (#658) * feat: admin login add version pb * feat: admin login add version --- internal/api/admin/admin.go | 4 + pkg/protocol/admin/admin.pb.go | 1755 ++++++++++++++++---------------- pkg/protocol/admin/admin.proto | 1 + 3 files changed, 889 insertions(+), 871 deletions(-) diff --git a/internal/api/admin/admin.go b/internal/api/admin/admin.go index c54c51581..4e7875d63 100644 --- a/internal/api/admin/admin.go +++ b/internal/api/admin/admin.go @@ -52,6 +52,10 @@ func (o *Api) AdminLogin(c *gin.Context) { apiresp.GinError(c, err) return } + if req.Version == "" { + apiresp.GinError(c, errs.New("openim-admin-front version too old, please use new version").Wrap()) + return + } loginResp, err := o.adminClient.Login(c, req) if err != nil { apiresp.GinError(c, err) diff --git a/pkg/protocol/admin/admin.pb.go b/pkg/protocol/admin/admin.pb.go index 309326fbe..0dd3a549a 100644 --- a/pkg/protocol/admin/admin.pb.go +++ b/pkg/protocol/admin/admin.pb.go @@ -43,7 +43,11 @@ const ( // login type LoginReq struct { - state protoimpl.MessageState + state protoimpl.MessageState `protogen:"open.v1"` + Account string `protobuf:"bytes,1,opt,name=account,proto3" json:"account"` + Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password"` + Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version"` + unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -97,6 +101,13 @@ func (x *LoginReq) GetPassword() string { return "" } +func (x *LoginReq) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + type LoginResp struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -6089,909 +6100,911 @@ var file_admin_admin_proto_rawDesc = []byte{ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x11, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2f, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x70, 0x62, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x70, 0x62, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x40, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x5a, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 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, 0xbd, 0x01, 0x0a, 0x09, 0x4c, 0x6f, 0x67, - 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x41, - 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, - 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, - 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, - 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, - 0x4c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, - 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x55, - 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x64, 0x6d, - 0x69, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x22, 0x80, 0x01, 0x0a, 0x12, 0x41, 0x64, 0x64, - 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x12, - 0x18, 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 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, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x12, - 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x15, 0x0a, 0x13, 0x41, - 0x64, 0x64, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x22, 0xab, 0x02, 0x0a, 0x12, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x12, 0x36, 0x0a, 0x07, 0x61, 0x63, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, - 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, - 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x12, 0x38, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x36, 0x0a, 0x07, 0x66, - 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, - 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, - 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x66, 0x61, 0x63, 0x65, - 0x55, 0x52, 0x4c, 0x12, 0x38, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x31, 0x0a, - 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6f, - 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, - 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, - 0x22, 0x63, 0x0a, 0x13, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, - 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, - 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x66, - 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, 0x61, - 0x63, 0x65, 0x55, 0x52, 0x4c, 0x22, 0x2f, 0x0a, 0x11, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, - 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, - 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, - 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x14, 0x0a, 0x12, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x22, 0x11, 0x0a, 0x0f, - 0x47, 0x65, 0x74, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x22, - 0x7c, 0x0a, 0x16, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x61, - 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, - 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, - 0x44, 0x12, 0x28, 0x0a, 0x0f, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x50, 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, 0x20, 0x0a, 0x0b, 0x6e, - 0x65, 0x77, 0x50, 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, 0x19, 0x0a, - 0x17, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, - 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x22, 0x2e, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x41, - 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x12, 0x18, - 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x22, 0x15, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x41, - 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x22, - 0x58, 0x0a, 0x15, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, - 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, - 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, - 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x74, 0x0a, 0x16, 0x53, 0x65, 0x61, + 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x22, 0xbd, 0x01, 0x0a, 0x09, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x18, 0x0a, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, + 0x76, 0x65, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, + 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x55, 0x73, 0x65, 0x72, + 0x49, 0x44, 0x22, 0x80, 0x01, 0x0a, 0x12, 0x41, 0x64, 0x64, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 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, 0x12, + 0x18, 0x0a, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, + 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, + 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x15, 0x0a, 0x13, 0x41, 0x64, 0x64, 0x41, 0x64, 0x6d, 0x69, + 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x22, 0xab, 0x02, 0x0a, + 0x12, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x65, 0x71, 0x12, 0x36, 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x38, 0x0a, 0x08, 0x70, + 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x70, 0x61, 0x73, + 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x36, 0x0a, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x12, 0x38, 0x0a, + 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x6e, + 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x31, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x63, 0x0a, 0x13, 0x41, 0x64, + 0x6d, 0x69, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, + 0x70, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, + 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, + 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x22, + 0x2f, 0x0a, 0x11, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, + 0x64, 0x52, 0x65, 0x71, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, + 0x22, 0x14, 0x0a, 0x12, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, + 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x22, 0x11, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x41, 0x64, 0x6d, + 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x22, 0x7c, 0x0a, 0x16, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, + 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x28, 0x0a, 0x0f, 0x63, + 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x50, 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, 0x20, 0x0a, 0x0b, 0x6e, 0x65, 0x77, 0x50, 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, 0x19, 0x0a, 0x17, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, + 0x73, 0x70, 0x22, 0x2e, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, + 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, + 0x44, 0x73, 0x22, 0x15, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x22, 0x58, 0x0a, 0x15, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x44, 0x0a, 0x0d, 0x61, 0x64, 0x6d, - 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, - 0x47, 0x65, 0x74, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, - 0x52, 0x0d, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x22, - 0xcc, 0x01, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, - 0x52, 0x65, 0x73, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, - 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x61, - 0x63, 0x65, 0x55, 0x52, 0x4c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, 0x61, 0x63, - 0x65, 0x55, 0x52, 0x4c, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, - 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, - 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1e, - 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x2f, - 0x0a, 0x13, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, - 0x6e, 0x64, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x22, - 0x16, 0x0a, 0x14, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, - 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x22, 0x2f, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x44, 0x65, - 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x12, 0x18, - 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x22, 0x16, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x44, - 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, - 0x22, 0x16, 0x0a, 0x14, 0x46, 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, - 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x22, 0x31, 0x0a, 0x15, 0x46, 0x69, 0x6e, 0x64, + 0x65, 0x71, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, + 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x22, 0x74, 0x0a, 0x16, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x64, 0x6d, + 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, + 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x74, 0x6f, + 0x74, 0x61, 0x6c, 0x12, 0x44, 0x0a, 0x0d, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x64, 0x6d, + 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x52, 0x0d, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x22, 0xcc, 0x01, 0x0a, 0x10, 0x47, 0x65, + 0x74, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x18, + 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, + 0x77, 0x6f, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, + 0x77, 0x6f, 0x72, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x12, 0x1a, + 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, + 0x65, 0x72, 0x49, 0x44, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, + 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x2f, 0x0a, 0x13, 0x41, 0x64, 0x64, 0x44, + 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x12, + 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x22, 0x16, 0x0a, 0x14, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, - 0x70, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x22, 0x73, 0x0a, 0x16, 0x53, - 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, - 0x6e, 0x64, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x12, - 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, + 0x70, 0x22, 0x2f, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, + 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, + 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, + 0x44, 0x73, 0x22, 0x16, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, + 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x22, 0x16, 0x0a, 0x14, 0x46, 0x69, + 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, + 0x65, 0x71, 0x22, 0x31, 0x0a, 0x15, 0x46, 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x75, + 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x75, 0x73, + 0x65, 0x72, 0x49, 0x44, 0x73, 0x22, 0x73, 0x0a, 0x16, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, + 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x12, + 0x18, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, + 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, + 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x88, 0x01, 0x0a, 0x16, 0x44, + 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x41, 0x74, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1e, 0x0a, + 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x36, 0x0a, + 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x55, 0x73, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x6b, 0x0a, 0x17, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, + 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x3a, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, + 0x6e, 0x64, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x05, 0x75, 0x73, 0x65, + 0x72, 0x73, 0x22, 0x30, 0x0a, 0x12, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x12, 0x1a, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, + 0x70, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x67, 0x72, 0x6f, 0x75, + 0x70, 0x49, 0x44, 0x73, 0x22, 0x15, 0x0a, 0x13, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x22, 0x30, 0x0a, 0x12, 0x44, + 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, + 0x71, 0x12, 0x1a, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x73, 0x22, 0x15, 0x0a, + 0x13, 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x52, 0x65, 0x73, 0x70, 0x22, 0x15, 0x0a, 0x13, 0x46, 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x22, 0x32, 0x0a, 0x14, 0x46, + 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, + 0x65, 0x73, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x73, 0x22, + 0x72, 0x0a, 0x15, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x77, + 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, + 0x72, 0x64, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, + 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x22, 0x79, 0x0a, 0x0e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x41, 0x74, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x12, + 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, + 0x2d, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x4a, + 0x0a, 0x16, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, + 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x1a, + 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x73, 0x22, 0x2c, 0x0a, 0x14, 0x41, 0x64, + 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, + 0x65, 0x71, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x05, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x22, 0x17, 0x0a, 0x15, 0x41, 0x64, 0x64, 0x49, + 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x22, 0x50, 0x0a, 0x14, 0x47, 0x65, 0x6e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x6c, 0x65, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6c, 0x65, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x6e, + 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6e, 0x75, 0x6d, 0x12, 0x14, 0x0a, + 0x05, 0x63, 0x68, 0x61, 0x72, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x63, 0x68, + 0x61, 0x72, 0x73, 0x22, 0x17, 0x0a, 0x15, 0x47, 0x65, 0x6e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0x2d, 0x0a, 0x15, + 0x46, 0x69, 0x6e, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, + 0x64, 0x65, 0x52, 0x65, 0x71, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x22, 0x50, 0x0a, 0x16, 0x46, + 0x69, 0x6e, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x36, 0x0a, 0x05, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x05, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x22, 0x42, 0x0a, + 0x14, 0x55, 0x73, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, + 0x64, 0x65, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, + 0x72, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, + 0x44, 0x22, 0x17, 0x0a, 0x15, 0x55, 0x73, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0x2c, 0x0a, 0x14, 0x44, 0x65, + 0x6c, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, + 0x65, 0x71, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x05, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x22, 0x17, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x49, + 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x22, 0xbc, 0x01, 0x0a, 0x12, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x26, 0x0a, 0x0e, 0x69, 0x6e, 0x76, 0x69, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0e, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, + 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, + 0x12, 0x1e, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x75, 0x73, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, + 0x12, 0x3e, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x75, 0x73, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, + 0x22, 0xbc, 0x01, 0x0a, 0x17, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x6e, 0x76, 0x69, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x12, 0x14, + 0x0a, 0x05, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x63, + 0x6f, 0x64, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x3f, + 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, + 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, + 0x66, 0x0a, 0x18, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, + 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, + 0x6c, 0x12, 0x34, 0x0a, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x49, + 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x52, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x22, 0x76, 0x0a, 0x19, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, + 0x6e, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x3f, + 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, + 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, + 0x92, 0x01, 0x0a, 0x10, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, + 0x69, 0x6e, 0x49, 0x50, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x1e, 0x0a, 0x0a, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x36, 0x0a, 0x04, + 0x75, 0x73, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x55, 0x73, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, + 0x75, 0x73, 0x65, 0x72, 0x22, 0x6a, 0x0a, 0x1a, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, + 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x36, 0x0a, 0x06, 0x6c, 0x69, 0x6d, 0x69, + 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x55, 0x73, 0x65, + 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x49, 0x50, 0x52, 0x06, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, + 0x22, 0x3a, 0x0a, 0x10, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, + 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x22, 0x50, 0x0a, 0x16, + 0x41, 0x64, 0x64, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, + 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x36, 0x0a, 0x06, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, + 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x06, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x22, 0x19, + 0x0a, 0x17, 0x41, 0x64, 0x64, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, + 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x22, 0x50, 0x0a, 0x16, 0x44, 0x65, 0x6c, + 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, + 0x52, 0x65, 0x71, 0x12, 0x36, 0x0a, 0x06, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, + 0x67, 0x69, 0x6e, 0x52, 0x06, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x22, 0x19, 0x0a, 0x17, 0x44, + 0x65, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, + 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x22, 0x83, 0x01, 0x0a, 0x0b, 0x49, 0x50, 0x46, 0x6f, 0x72, + 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x24, 0x0a, 0x0d, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x6c, + 0x69, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, + 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0a, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x66, 0x0a, 0x0e, + 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x41, 0x64, 0x64, 0x12, 0x0e, + 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x24, + 0x0a, 0x0d, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, + 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x4c, + 0x6f, 0x67, 0x69, 0x6e, 0x22, 0x89, 0x01, 0x0a, 0x14, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, + 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, + 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, + 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x22, 0x88, 0x01, 0x0a, 0x16, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, - 0x6e, 0x64, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x75, - 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, - 0x72, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, - 0x69, 0x6d, 0x65, 0x12, 0x36, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, - 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x6b, 0x0a, 0x17, 0x53, - 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, - 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x3a, 0x0a, 0x05, - 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6f, 0x70, - 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x66, 0x61, 0x75, - 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, - 0x65, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x22, 0x30, 0x0a, 0x12, 0x41, 0x64, 0x64, 0x44, - 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x12, 0x1a, - 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x73, 0x22, 0x15, 0x0a, 0x13, 0x41, 0x64, - 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, - 0x70, 0x22, 0x30, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, - 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x12, 0x1a, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, - 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, - 0x49, 0x44, 0x73, 0x22, 0x15, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, - 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x22, 0x15, 0x0a, 0x13, 0x46, 0x69, - 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, - 0x71, 0x22, 0x32, 0x0a, 0x14, 0x46, 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x67, 0x72, 0x6f, - 0x75, 0x70, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x67, 0x72, 0x6f, - 0x75, 0x70, 0x49, 0x44, 0x73, 0x22, 0x72, 0x0a, 0x15, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, - 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x12, 0x18, - 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, - 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, - 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, - 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x79, 0x0a, 0x0e, 0x47, 0x72, 0x6f, - 0x75, 0x70, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x67, - 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x72, - 0x6f, 0x75, 0x70, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, - 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, - 0x6b, 0x77, 0x73, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x67, - 0x72, 0x6f, 0x75, 0x70, 0x22, 0x4a, 0x0a, 0x16, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x65, - 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, - 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x74, - 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x73, - 0x22, 0x2c, 0x0a, 0x14, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x64, 0x65, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x22, 0x17, - 0x0a, 0x15, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, - 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0x50, 0x0a, 0x14, 0x47, 0x65, 0x6e, 0x49, 0x6e, - 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x12, - 0x10, 0x0a, 0x03, 0x6c, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6c, 0x65, - 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x6e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, - 0x6e, 0x75, 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x68, 0x61, 0x72, 0x73, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x63, 0x68, 0x61, 0x72, 0x73, 0x22, 0x17, 0x0a, 0x15, 0x47, 0x65, 0x6e, - 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x22, 0x2d, 0x0a, 0x15, 0x46, 0x69, 0x6e, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x12, 0x14, 0x0a, 0x05, 0x63, - 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x63, 0x6f, 0x64, 0x65, - 0x73, 0x22, 0x50, 0x0a, 0x16, 0x46, 0x69, 0x6e, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x36, 0x0a, 0x05, 0x63, - 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6f, 0x70, 0x65, - 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x05, 0x63, 0x6f, - 0x64, 0x65, 0x73, 0x22, 0x42, 0x0a, 0x14, 0x55, 0x73, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x63, - 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, - 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x22, 0x17, 0x0a, 0x15, 0x55, 0x73, 0x65, 0x49, 0x6e, - 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x22, 0x2c, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x64, 0x65, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x22, 0x17, - 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, - 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x22, 0xbc, 0x01, 0x0a, 0x12, 0x49, 0x6e, 0x76, 0x69, - 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x26, - 0x0a, 0x0e, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x54, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x64, 0x55, 0x73, - 0x65, 0x72, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x75, 0x73, 0x65, 0x64, - 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x3e, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x64, 0x55, 0x73, - 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, - 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x55, 0x73, - 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x75, 0x73, - 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x22, 0xbc, 0x01, 0x0a, 0x17, 0x53, 0x65, 0x61, 0x72, 0x63, - 0x68, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, - 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, - 0x65, 0x72, 0x49, 0x44, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x75, 0x73, 0x65, - 0x72, 0x49, 0x44, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x03, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x05, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6b, 0x65, - 0x79, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, - 0x77, 0x6f, 0x72, 0x64, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, - 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, - 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x66, 0x0a, 0x18, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, - 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x34, 0x0a, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, - 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x22, 0x76, 0x0a, - 0x19, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, - 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x6b, 0x65, - 0x79, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, - 0x77, 0x6f, 0x72, 0x64, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, - 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, - 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x92, 0x01, 0x0a, 0x10, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x55, - 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x49, 0x50, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, - 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, - 0x49, 0x44, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, - 0x69, 0x70, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, - 0x6d, 0x65, 0x12, 0x36, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x6a, 0x0a, 0x1a, 0x53, 0x65, - 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, - 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, - 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x36, - 0x0a, 0x06, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, - 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x4c, 0x69, - 0x6d, 0x69, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x49, 0x50, 0x52, 0x06, - 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x22, 0x3a, 0x0a, 0x10, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, - 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, - 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, - 0x49, 0x44, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, - 0x69, 0x70, 0x22, 0x50, 0x0a, 0x16, 0x41, 0x64, 0x64, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, - 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x36, 0x0a, 0x06, - 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, - 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x73, 0x65, 0x72, - 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x06, 0x6c, 0x69, - 0x6d, 0x69, 0x74, 0x73, 0x22, 0x19, 0x0a, 0x17, 0x41, 0x64, 0x64, 0x55, 0x73, 0x65, 0x72, 0x49, - 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x22, - 0x50, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, - 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x36, 0x0a, 0x06, 0x6c, 0x69, 0x6d, - 0x69, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, - 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, - 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x06, 0x6c, 0x69, 0x6d, 0x69, 0x74, - 0x73, 0x22, 0x19, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, - 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x22, 0x83, 0x01, 0x0a, - 0x0b, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x12, 0x0e, 0x0a, 0x02, - 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x24, 0x0a, 0x0d, - 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0d, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, - 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, - 0x69, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, - 0x6d, 0x65, 0x22, 0x66, 0x0a, 0x0e, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, - 0x6e, 0x41, 0x64, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x02, 0x69, 0x70, 0x12, 0x24, 0x0a, 0x0d, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x67, - 0x69, 0x73, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x6c, 0x69, 0x6d, - 0x69, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x6c, 0x69, - 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, - 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x22, 0x89, 0x01, 0x0a, 0x14, 0x53, - 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, - 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x16, 0x0a, - 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, - 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, - 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x68, 0x0a, 0x15, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, - 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, - 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, - 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x39, 0x0a, 0x0a, 0x66, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, - 0x65, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6f, 0x70, 0x65, 0x6e, - 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, - 0x64, 0x64, 0x65, 0x6e, 0x52, 0x0a, 0x66, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x73, - 0x22, 0x51, 0x0a, 0x11, 0x41, 0x64, 0x64, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, - 0x65, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x3c, 0x0a, 0x0a, 0x66, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, - 0x65, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, - 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, - 0x64, 0x64, 0x65, 0x6e, 0x41, 0x64, 0x64, 0x52, 0x0a, 0x66, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, - 0x65, 0x6e, 0x73, 0x22, 0x14, 0x0a, 0x12, 0x41, 0x64, 0x64, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, - 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x22, 0x25, 0x0a, 0x11, 0x44, 0x65, 0x6c, - 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x10, - 0x0a, 0x03, 0x69, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x69, 0x70, 0x73, - 0x22, 0x14, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, - 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x22, 0x2b, 0x0a, 0x19, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, - 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x02, 0x69, 0x70, 0x22, 0x1c, 0x0a, 0x1a, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x65, 0x72, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x22, 0x40, 0x0a, 0x16, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x46, - 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, - 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x75, - 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, - 0x72, 0x49, 0x44, 0x22, 0x19, 0x0a, 0x17, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4c, 0x6f, 0x67, 0x69, - 0x6e, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x22, 0x45, - 0x0a, 0x13, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x73, - 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x16, 0x0a, - 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, - 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x16, 0x0a, 0x14, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x22, 0x3e, 0x0a, - 0x0c, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, - 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, - 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x0f, 0x0a, - 0x0d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x22, 0x2a, - 0x0a, 0x0e, 0x55, 0x6e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, - 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x22, 0x11, 0x0a, 0x0f, 0x55, 0x6e, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x22, 0x6f, 0x0a, - 0x12, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, - 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x3f, 0x0a, - 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, - 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xb7, - 0x02, 0x0a, 0x0d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, - 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, - 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x65, 0x61, 0x43, 0x6f, 0x64, 0x65, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x72, 0x65, 0x61, 0x43, 0x6f, 0x64, 0x65, - 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, - 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x12, 0x16, 0x0a, 0x06, - 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x67, 0x65, - 0x6e, 0x64, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x09, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, - 0x6f, 0x70, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x6f, 0x70, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x5e, 0x0a, 0x13, 0x53, 0x65, 0x61, 0x72, - 0x63, 0x68, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, - 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, - 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x31, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, - 0x6f, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x22, 0x30, 0x0a, 0x14, 0x46, 0x69, 0x6e, 0x64, - 0x55, 0x73, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, - 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x73, 0x22, 0x77, 0x0a, 0x09, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, + 0x22, 0x68, 0x0a, 0x15, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, + 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, + 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, + 0x39, 0x0a, 0x0a, 0x66, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x0a, + 0x66, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x73, 0x22, 0x51, 0x0a, 0x11, 0x41, 0x64, + 0x64, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x12, + 0x3c, 0x0a, 0x0a, 0x66, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x41, 0x64, + 0x64, 0x52, 0x0a, 0x66, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x73, 0x22, 0x14, 0x0a, + 0x12, 0x41, 0x64, 0x64, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x22, 0x25, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, + 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x70, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x69, 0x70, 0x73, 0x22, 0x14, 0x0a, 0x12, 0x44, 0x65, + 0x6c, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x22, 0x2b, 0x0a, 0x19, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, + 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x22, 0x1c, 0x0a, + 0x1a, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x46, 0x6f, + 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x22, 0x40, 0x0a, 0x16, 0x43, + 0x68, 0x65, 0x63, 0x6b, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, + 0x65, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x22, 0x19, 0x0a, + 0x17, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x46, 0x6f, 0x72, 0x62, 0x69, + 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x22, 0x45, 0x0a, 0x13, 0x43, 0x61, 0x6e, 0x63, + 0x65, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, + 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, + 0x16, 0x0a, 0x14, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, + 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x22, 0x3e, 0x0a, 0x0c, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x6f, 0x70, 0x55, 0x73, 0x65, - 0x72, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6f, 0x70, 0x55, 0x73, 0x65, - 0x72, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, - 0x69, 0x6d, 0x65, 0x22, 0x48, 0x0a, 0x15, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x2f, 0x0a, 0x06, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6f, - 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x22, 0x44, 0x0a, - 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x12, + 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x0f, 0x0a, 0x0d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x22, 0x2a, 0x0a, 0x0e, 0x55, 0x6e, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, + 0x65, 0x72, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x75, 0x73, 0x65, + 0x72, 0x49, 0x44, 0x73, 0x22, 0x11, 0x0a, 0x0f, 0x55, 0x6e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x55, + 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x22, 0x6f, 0x0a, 0x12, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, + 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, + 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xb7, 0x02, 0x0a, 0x0d, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, + 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, + 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, + 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1a, + 0x0a, 0x08, 0x61, 0x72, 0x65, 0x61, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x61, 0x72, 0x65, 0x61, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, + 0x61, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, + 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x66, 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, + 0x61, 0x63, 0x65, 0x55, 0x52, 0x4c, 0x12, 0x16, 0x0a, 0x06, 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x16, + 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x6f, 0x70, 0x55, 0x73, 0x65, 0x72, + 0x49, 0x44, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6f, 0x70, 0x55, 0x73, 0x65, 0x72, + 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, + 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, + 0x6d, 0x65, 0x22, 0x5e, 0x0a, 0x13, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, + 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, + 0x31, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x75, 0x73, 0x65, + 0x72, 0x73, 0x22, 0x30, 0x0a, 0x14, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, + 0x65, 0x72, 0x49, 0x44, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x75, 0x73, 0x65, + 0x72, 0x49, 0x44, 0x73, 0x22, 0x77, 0x0a, 0x09, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x66, + 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, + 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, + 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x6f, 0x70, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x6f, 0x70, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1e, 0x0a, + 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x48, 0x0a, + 0x15, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x2f, 0x0a, 0x06, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x06, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x22, 0x44, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, + 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, + 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x18, 0x20, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x22, 0x27, 0x0a, + 0x0f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x25, 0x0a, 0x0d, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x72, 0x0a, + 0x0e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x54, - 0x79, 0x70, 0x65, 0x18, 0x20, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x54, - 0x79, 0x70, 0x65, 0x22, 0x27, 0x0a, 0x0f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x25, 0x0a, 0x0d, - 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x14, 0x0a, - 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, - 0x6b, 0x65, 0x6e, 0x22, 0x72, 0x0a, 0x0e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x6f, 0x6b, 0x65, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1a, 0x0a, - 0x08, 0x75, 0x73, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x08, 0x75, 0x73, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2c, 0x0a, 0x11, 0x65, 0x78, 0x70, - 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, - 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x22, 0x2c, 0x0a, 0x12, 0x49, 0x6e, 0x76, 0x61, 0x6c, - 0x69, 0x64, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, - 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, - 0x73, 0x65, 0x72, 0x49, 0x44, 0x22, 0x15, 0x0a, 0x13, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, - 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x22, 0x82, 0x02, 0x0a, - 0x0c, 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, - 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x61, 0x70, 0x70, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x75, - 0x72, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x10, 0x0a, - 0x03, 0x6d, 0x64, 0x35, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x64, 0x35, 0x12, - 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, - 0x69, 0x7a, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x08, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, - 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, - 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, - 0x65, 0x22, 0x0f, 0x0a, 0x0d, 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x22, 0x2c, 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, - 0x65, 0x71, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x49, 0x64, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x49, 0x64, 0x73, - 0x22, 0x0f, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, - 0x70, 0x22, 0xaf, 0x04, 0x0a, 0x0f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, - 0x65, 0x74, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x30, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, + 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x2c, 0x0a, 0x11, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, + 0x65, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, + 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, + 0x73, 0x22, 0x2c, 0x0a, 0x12, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, + 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x22, + 0x15, 0x0a, 0x13, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x22, 0x82, 0x02, 0x0a, 0x0c, 0x41, 0x64, 0x64, 0x41, 0x70, + 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x61, + 0x70, 0x70, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x70, 0x70, 0x49, + 0x44, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x64, 0x35, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x64, 0x35, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, + 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x0a, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0a, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x0f, 0x0a, 0x0d, 0x41, + 0x64, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x22, 0x2c, 0x0a, 0x0c, + 0x44, 0x65, 0x6c, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x12, 0x1c, 0x0a, 0x09, + 0x61, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x49, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x09, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x49, 0x64, 0x73, 0x22, 0x0f, 0x0a, 0x0d, 0x44, 0x65, + 0x6c, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x22, 0xaf, 0x04, 0x0a, 0x0f, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x30, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x32, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, + 0x61, 0x70, 0x70, 0x49, 0x44, 0x12, 0x30, 0x0a, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x32, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x49, 0x44, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x61, 0x70, 0x70, 0x49, 0x44, 0x12, 0x30, 0x0a, 0x04, 0x69, - 0x63, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x65, 0x52, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x2e, 0x0a, 0x03, 0x6d, 0x64, 0x35, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x52, 0x03, 0x6d, 0x64, 0x35, 0x12, 0x2f, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x36, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, - 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, - 0x03, 0x75, 0x72, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, - 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, - 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x2e, 0x0a, - 0x03, 0x6d, 0x64, 0x35, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, - 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, - 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x03, 0x6d, 0x64, 0x35, 0x12, 0x2f, 0x0a, - 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6f, 0x70, - 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, - 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x36, - 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, - 0x74, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, - 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, - 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, - 0x12, 0x34, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, - 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x3b, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x54, 0x69, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6f, 0x70, 0x65, - 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, - 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, - 0x69, 0x6d, 0x65, 0x22, 0x12, 0x0a, 0x10, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, - 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x22, 0x0f, 0x0a, 0x0d, 0x46, 0x69, 0x6e, 0x64, 0x41, - 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x22, 0x4a, 0x0a, 0x0e, 0x46, 0x69, 0x6e, 0x64, - 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x38, 0x0a, 0x07, 0x61, 0x70, - 0x70, 0x6c, 0x65, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x70, - 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x61, 0x70, 0x70, - 0x6c, 0x65, 0x74, 0x73, 0x22, 0x6c, 0x0a, 0x0f, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x70, - 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, - 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, - 0x64, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, - 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, - 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x22, 0x62, 0x0a, 0x10, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x70, 0x70, 0x6c, - 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x38, 0x0a, 0x07, - 0x61, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, - 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x61, - 0x70, 0x70, 0x6c, 0x65, 0x74, 0x73, 0x22, 0x95, 0x01, 0x0a, 0x12, 0x53, 0x65, 0x74, 0x43, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x12, 0x44, 0x0a, - 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, - 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x74, - 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x2e, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x1a, 0x39, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 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, 0x22, 0x15, - 0x0a, 0x13, 0x53, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x52, 0x65, 0x73, 0x70, 0x22, 0x28, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x43, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x6b, - 0x65, 0x79, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x22, - 0x15, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x22, 0x14, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x22, 0x97, 0x01, 0x0a, - 0x13, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x52, 0x65, 0x73, 0x70, 0x12, 0x45, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x39, 0x0a, 0x0b, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 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, 0x22, 0x29, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, - 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, - 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, - 0x44, 0x22, 0x9d, 0x01, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4b, 0x0a, 0x09, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, - 0x4d, 0x61, 0x70, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, - 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, - 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, - 0x4d, 0x61, 0x70, 0x1a, 0x3c, 0x0a, 0x0e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x4d, 0x61, 0x70, - 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, 0x05, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, - 0x01, 0x22, 0xe0, 0x01, 0x0a, 0x12, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, - 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, - 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x10, - 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, - 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x74, 0x65, 0x78, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x61, - 0x74, 0x65, 0x73, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x6c, 0x61, 0x74, 0x65, - 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x68, 0x6f, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x03, 0x68, 0x6f, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, - 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x54, 0x69, 0x6d, 0x65, 0x22, 0x53, 0x0a, 0x1b, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x41, 0x70, - 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x52, 0x65, 0x71, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, - 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x5a, 0x0a, 0x1c, 0x4c, 0x61, 0x74, - 0x65, 0x73, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x3a, 0x0a, 0x07, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6f, 0x70, 0x65, - 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xb6, 0x01, 0x0a, 0x18, 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, - 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x71, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, + 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x38, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x34, 0x0a, 0x06, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, + 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x12, 0x3b, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x0b, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x12, 0x0a, + 0x10, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x22, 0x0f, 0x0a, 0x0d, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, + 0x65, 0x71, 0x22, 0x4a, 0x0a, 0x0e, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x38, 0x0a, 0x07, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x63, + 0x68, 0x61, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x65, + 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x73, 0x22, 0x6c, + 0x0a, 0x0f, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, + 0x71, 0x12, 0x18, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x3f, 0x0a, 0x0a, 0x70, + 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x62, 0x0a, 0x10, + 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x38, 0x0a, 0x07, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x74, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x41, 0x70, 0x70, + 0x6c, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x73, + 0x22, 0x95, 0x01, 0x0a, 0x12, 0x53, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x12, 0x44, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x39, 0x0a, + 0x0b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 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, 0x22, 0x15, 0x0a, 0x13, 0x53, 0x65, 0x74, 0x43, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x22, + 0x28, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x52, 0x65, 0x71, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x22, 0x15, 0x0a, 0x13, 0x44, 0x65, 0x6c, + 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, + 0x22, 0x14, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x22, 0x97, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x43, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x45, + 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, + 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, + 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x39, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 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, + 0x22, 0x29, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x44, 0x22, 0x9d, 0x01, 0x0a, 0x10, + 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x4b, 0x0a, 0x09, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x4d, 0x61, 0x70, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x09, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x4d, 0x61, 0x70, 0x1a, 0x3c, 0x0a, + 0x0e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x4d, 0x61, 0x70, 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, 0x05, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xe0, 0x01, 0x0a, 0x12, + 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, + 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x18, - 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, - 0x78, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, 0x14, - 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, - 0x6f, 0x72, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x18, 0x06, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, + 0x78, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, 0x14, + 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, + 0x6f, 0x72, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, - 0x68, 0x6f, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x68, 0x6f, 0x74, 0x22, 0x1b, - 0x0a, 0x19, 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x22, 0x95, 0x03, 0x0a, 0x1b, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x38, 0x0a, 0x08, 0x70, - 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, - 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x70, 0x6c, 0x61, - 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x36, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, - 0x03, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, - 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, - 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x30, 0x0a, - 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, - 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, - 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, - 0x30, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, - 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, - 0x65, 0x12, 0x32, 0x0a, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x6c, - 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x03, 0x68, 0x6f, 0x74, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x03, - 0x68, 0x6f, 0x74, 0x22, 0x1e, 0x0a, 0x1c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, - 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x73, 0x70, 0x22, 0x2d, 0x0a, 0x1b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x70, + 0x68, 0x6f, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x68, 0x6f, 0x74, 0x12, 0x1e, + 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x53, + 0x0a, 0x1b, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x1a, 0x0a, + 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x22, 0x5a, 0x0a, 0x1c, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x02, - 0x69, 0x64, 0x22, 0x1e, 0x0a, 0x1c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x22, 0x78, 0x0a, 0x19, 0x50, 0x61, 0x67, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x12, - 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x3f, 0x0a, 0x0a, 0x70, - 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x70, 0x0a, 0x1a, + 0x65, 0x73, 0x70, 0x12, 0x3a, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, + 0xb6, 0x01, 0x0a, 0x18, 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x1a, 0x0a, 0x08, + 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x75, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, + 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x16, + 0x0a, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, + 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x68, 0x6f, 0x74, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x03, 0x68, 0x6f, 0x74, 0x22, 0x1b, 0x0a, 0x19, 0x41, 0x64, 0x64, 0x41, + 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x22, 0x95, 0x03, 0x0a, 0x1b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x38, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, + 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, + 0x36, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x30, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, 0x30, 0x0a, 0x05, 0x66, 0x6f, 0x72, + 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x32, 0x0a, 0x06, 0x6c, + 0x61, 0x74, 0x65, 0x73, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, + 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, + 0x2c, 0x0a, 0x03, 0x68, 0x6f, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, + 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x03, 0x68, 0x6f, 0x74, 0x22, 0x1e, 0x0a, + 0x1c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x22, 0x2d, 0x0a, + 0x1b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x1e, 0x0a, 0x1c, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x22, 0x78, 0x0a, 0x19, 0x50, 0x61, 0x67, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, - 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, - 0x12, 0x3c, 0x0a, 0x08, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, - 0x6e, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0xee, - 0x24, 0x0a, 0x05, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x12, 0x38, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, - 0x6e, 0x12, 0x16, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, - 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x6f, 0x70, 0x65, 0x6e, - 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x12, 0x53, 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, - 0x77, 0x6f, 0x72, 0x64, 0x12, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, - 0x72, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, - 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, - 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x41, 0x64, 0x6d, 0x69, 0x6e, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, - 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, - 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x6d, 0x69, - 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, - 0x4d, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, - 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, - 0x65, 0x74, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x1e, - 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, - 0x74, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, - 0x0a, 0x0f, 0x41, 0x64, 0x64, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, - 0x2e, 0x41, 0x64, 0x64, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, - 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x62, 0x0a, 0x13, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x24, 0x2e, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, + 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, + 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x73, 0x64, 0x6b, 0x77, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, + 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x70, 0x0a, 0x1a, 0x50, 0x61, 0x67, 0x65, 0x41, 0x70, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x3c, 0x0a, 0x08, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x70, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x08, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0xee, 0x24, 0x0a, 0x05, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x12, 0x38, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x16, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, + 0x52, 0x65, 0x71, 0x1a, 0x17, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x53, 0x0a, 0x0e, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x1f, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x1a, + 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, + 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4d, 0x0a, 0x0c, 0x47, 0x65, 0x74, + 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x64, 0x6d, 0x69, + 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x64, 0x6d, 0x69, 0x6e, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x41, 0x64, 0x64, 0x41, + 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x20, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x64, + 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, + 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x62, 0x0a, 0x13, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x50, + 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x64, 0x6d, + 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, - 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, - 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x61, - 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x44, 0x65, - 0x6c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x20, 0x2e, - 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, - 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, - 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, - 0x65, 0x6c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x12, 0x5f, 0x0a, 0x12, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x64, 0x6d, 0x69, - 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, - 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x64, - 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x24, 0x2e, - 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, - 0x72, 0x63, 0x68, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x12, 0x59, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, - 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x12, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, - 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, - 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x6f, 0x70, 0x65, - 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, - 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x59, - 0x0a, 0x10, 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, - 0x6e, 0x64, 0x12, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, - 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, - 0x6e, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, - 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, - 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, 0x46, 0x69, 0x6e, - 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x12, 0x22, - 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, - 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, - 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, - 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, - 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x62, 0x0a, 0x13, 0x53, 0x65, 0x61, 0x72, 0x63, - 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x12, 0x24, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x44, 0x65, 0x6c, 0x41, 0x64, 0x6d, 0x69, 0x6e, + 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x41, 0x64, 0x6d, 0x69, + 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5f, 0x0a, 0x12, + 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x64, 0x6d, + 0x69, 0x6e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x59, 0x0a, + 0x10, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, + 0x64, 0x12, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, + 0x64, 0x52, 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, + 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x59, 0x0a, 0x10, 0x44, 0x65, 0x6c, 0x44, + 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x12, 0x21, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x44, + 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x1a, + 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, + 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, + 0x65, 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, 0x46, 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, + 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, + 0x70, 0x12, 0x62, 0x0a, 0x13, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x12, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, - 0x64, 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, - 0x74, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x41, - 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x20, - 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, - 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, - 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, - 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, - 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, - 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, - 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, - 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, - 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x59, 0x0a, 0x10, 0x46, - 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, - 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, - 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, - 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, - 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, - 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5f, 0x0a, 0x12, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, - 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x23, 0x2e, 0x6f, - 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, - 0x63, 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, - 0x71, 0x1a, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, - 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, - 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, 0x41, 0x64, 0x64, 0x49, 0x6e, - 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x22, 0x2e, 0x6f, - 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x49, - 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, - 0x1a, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, - 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, 0x47, 0x65, 0x6e, 0x49, 0x6e, 0x76, 0x69, - 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, - 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x6e, 0x49, 0x6e, 0x76, - 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x23, - 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, - 0x6e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x12, 0x5f, 0x0a, 0x12, 0x46, 0x69, 0x6e, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, - 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x49, 0x6e, 0x76, - 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x24, - 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, - 0x6e, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, 0x55, 0x73, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, - 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x73, 0x65, 0x49, 0x6e, 0x76, 0x69, - 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, - 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x73, 0x65, - 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, - 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, - 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x49, 0x6e, - 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x12, 0x65, 0x0a, 0x14, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, - 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x6e, - 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, - 0x26, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, - 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, - 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x6b, 0x0a, 0x16, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x64, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x44, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, + 0x0f, 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, + 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, + 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, + 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x59, 0x0a, 0x10, 0x46, 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x44, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, + 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, + 0x12, 0x5f, 0x0a, 0x12, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x44, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x1a, 0x24, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, + 0x70, 0x12, 0x5c, 0x0a, 0x11, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x76, + 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x5c, 0x0a, 0x11, 0x47, 0x65, 0x6e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x43, 0x6f, 0x64, 0x65, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x6e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x6e, 0x49, 0x6e, 0x76, 0x69, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5f, 0x0a, + 0x12, 0x46, 0x69, 0x6e, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, + 0x6f, 0x64, 0x65, 0x12, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x49, 0x6e, 0x76, 0x69, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5c, + 0x0a, 0x11, 0x55, 0x73, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, + 0x6f, 0x64, 0x65, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x55, 0x73, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x73, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, + 0x44, 0x65, 0x6c, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, + 0x65, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x44, 0x65, 0x6c, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, + 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x65, 0x0a, 0x14, 0x53, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, + 0x64, 0x65, 0x12, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x26, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, + 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x12, 0x6b, 0x0a, 0x16, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x49, + 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x27, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, - 0x6e, 0x12, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, - 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, - 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x28, 0x2e, 0x6f, 0x70, 0x65, - 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, - 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, - 0x52, 0x65, 0x73, 0x70, 0x12, 0x62, 0x0a, 0x13, 0x41, 0x64, 0x64, 0x55, 0x73, 0x65, 0x72, 0x49, - 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x24, 0x2e, 0x6f, 0x70, + 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x28, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, + 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x62, + 0x0a, 0x13, 0x41, 0x64, 0x64, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, + 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, + 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, - 0x71, 0x1a, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, - 0x2e, 0x41, 0x64, 0x64, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, - 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x62, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x55, - 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, - 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, + 0x73, 0x70, 0x12, 0x62, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, + 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x55, 0x73, 0x65, 0x72, + 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x1a, + 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, - 0x69, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, - 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x49, 0x50, 0x4c, 0x69, - 0x6d, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, - 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, - 0x6e, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, - 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, - 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, - 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x50, 0x46, 0x6f, 0x72, - 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x53, 0x0a, 0x0e, 0x41, 0x64, - 0x64, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x12, 0x1f, 0x2e, 0x6f, - 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x49, - 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, - 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, - 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, - 0x53, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, - 0x6e, 0x12, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, - 0x2e, 0x44, 0x65, 0x6c, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, - 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, - 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, - 0x52, 0x65, 0x73, 0x70, 0x12, 0x59, 0x0a, 0x10, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x12, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, - 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x6f, 0x70, - 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, - 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, - 0x44, 0x0a, 0x09, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1a, 0x2e, 0x6f, - 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, - 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, - 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4a, 0x0a, 0x0b, 0x55, 0x6e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x55, 0x73, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x6e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, - 0x65, 0x71, 0x1a, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, - 0x6e, 0x2e, 0x55, 0x6e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, - 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x6c, 0x6f, 0x63, 0x6b, - 0x55, 0x73, 0x65, 0x72, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, - 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, - 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, 0x46, 0x69, 0x6e, - 0x64, 0x55, 0x73, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x22, - 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, - 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, - 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, - 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x6b, 0x0a, 0x16, 0x43, 0x68, 0x65, 0x63, 0x6b, + 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, + 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x12, 0x22, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, + 0x23, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x53, 0x0a, 0x0e, 0x41, 0x64, 0x64, 0x49, 0x50, 0x46, 0x6f, 0x72, + 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x12, 0x1f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, + 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, + 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x53, 0x0a, 0x0e, 0x44, 0x65, 0x6c, + 0x49, 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x12, 0x1f, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x49, 0x50, + 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x20, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x49, + 0x50, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x59, + 0x0a, 0x10, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x73, + 0x65, 0x72, 0x12, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x73, + 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x44, 0x0a, 0x09, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, + 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x4a, 0x0a, 0x0b, 0x55, 0x6e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1c, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x6e, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x1a, 0x1d, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x6e, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x53, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x12, 0x20, + 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, + 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, + 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x55, 0x73, 0x65, 0x72, 0x52, + 0x65, 0x73, 0x70, 0x12, 0x5c, 0x0a, 0x11, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x22, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x23, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, + 0x55, 0x73, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, + 0x70, 0x12, 0x6b, 0x0a, 0x16, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x12, 0x27, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, - 0x6e, 0x12, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, - 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x46, 0x6f, - 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x28, 0x2e, 0x6f, 0x70, 0x65, - 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, - 0x52, 0x65, 0x73, 0x70, 0x12, 0x62, 0x0a, 0x13, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4c, 0x6f, 0x67, - 0x69, 0x6e, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x12, 0x24, 0x2e, 0x6f, 0x70, + 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x28, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x62, + 0x0a, 0x13, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x46, 0x6f, 0x72, 0x62, + 0x69, 0x64, 0x64, 0x65, 0x6e, 0x12, 0x24, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x46, + 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, - 0x71, 0x1a, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, - 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x46, 0x6f, 0x72, 0x62, 0x69, - 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4a, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, - 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, - 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, - 0x52, 0x65, 0x73, 0x70, 0x12, 0x47, 0x0a, 0x0a, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x12, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, - 0x6e, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, - 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x50, - 0x61, 0x72, 0x73, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x44, 0x0a, - 0x09, 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x12, 0x1a, 0x2e, 0x6f, 0x70, 0x65, - 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, + 0x73, 0x70, 0x12, 0x4a, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x12, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, + 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x47, + 0x0a, 0x0a, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1b, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x50, 0x61, 0x72, 0x73, + 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x44, 0x0a, 0x09, 0x41, 0x64, 0x64, 0x41, 0x70, + 0x70, 0x6c, 0x65, 0x74, 0x12, 0x1a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, + 0x1a, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, + 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x44, 0x0a, + 0x09, 0x44, 0x65, 0x6c, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x12, 0x1a, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, - 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x12, 0x44, 0x0a, 0x09, 0x44, 0x65, 0x6c, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, - 0x12, 0x1a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, - 0x44, 0x65, 0x6c, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6f, - 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x41, - 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4d, 0x0a, 0x0c, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x12, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, - 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, - 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, - 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, - 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x47, 0x0a, 0x0a, 0x46, 0x69, 0x6e, 0x64, - 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x12, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, - 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, - 0x52, 0x65, 0x71, 0x1a, 0x1c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, - 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, - 0x70, 0x12, 0x4d, 0x0a, 0x0c, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x70, 0x70, 0x6c, 0x65, - 0x74, 0x12, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, - 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, - 0x1a, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, - 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x12, 0x56, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, - 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, - 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x53, 0x65, 0x74, 0x43, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x2e, 0x6f, 0x70, - 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x74, 0x43, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, - 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x74, - 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, - 0x12, 0x56, 0x0a, 0x0f, 0x44, 0x65, 0x6c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, - 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, - 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4d, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x55, - 0x73, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, - 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, - 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x49, 0x6e, 0x76, 0x61, 0x6c, - 0x69, 0x64, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, - 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, - 0x64, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, - 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x49, 0x6e, 0x76, 0x61, - 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, - 0x71, 0x0a, 0x18, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x6f, 0x70, - 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x4c, 0x61, 0x74, 0x65, 0x73, - 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x2a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, - 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x41, 0x70, 0x70, 0x6c, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x12, 0x68, 0x0a, 0x15, 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x2e, 0x6f, 0x70, - 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x70, - 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x52, 0x65, 0x71, 0x1a, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, - 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x71, 0x0a, 0x18, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, - 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, - 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x52, 0x65, 0x71, 0x1a, 0x2a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, - 0x69, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, - 0x71, 0x0a, 0x18, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x6f, 0x70, - 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x2a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, - 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x12, 0x6b, 0x0a, 0x16, 0x50, 0x61, 0x67, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x2e, 0x6f, - 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x50, 0x61, 0x67, 0x65, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x12, 0x4d, 0x0a, 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, + 0x6c, 0x65, 0x74, 0x12, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, + 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x47, 0x0a, 0x0a, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, + 0x12, 0x1b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, + 0x46, 0x69, 0x6e, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1c, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6e, + 0x64, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4d, 0x0a, 0x0c, 0x53, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x12, 0x1d, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, + 0x41, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x47, 0x65, + 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, 0x65, 0x74, + 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x1a, + 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x47, + 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x53, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x53, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x44, 0x65, + 0x6c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x20, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, + 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x1a, + 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, + 0x65, 0x6c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, + 0x73, 0x70, 0x12, 0x4d, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x12, 0x1d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, + 0x71, 0x1a, 0x1e, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, + 0x70, 0x12, 0x56, 0x0a, 0x0f, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x20, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x21, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x71, 0x0a, 0x18, 0x4c, 0x61, 0x74, + 0x65, 0x73, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, + 0x1a, 0x2a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, + 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x68, 0x0a, 0x15, + 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x27, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x64, 0x64, + 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x71, 0x0a, 0x18, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x28, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, - 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x42, - 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, - 0x65, 0x6e, 0x69, 0x6d, 0x73, 0x64, 0x6b, 0x2f, 0x63, 0x68, 0x61, 0x74, 0x2f, 0x70, 0x6b, 0x67, - 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x2a, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x71, 0x0a, 0x18, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, + 0x1a, 0x2a, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x6b, 0x0a, 0x16, + 0x50, 0x61, 0x67, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x1a, + 0x28, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x50, + 0x61, 0x67, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6d, 0x73, 0x64, + 0x6b, 0x2f, 0x63, 0x68, 0x61, 0x74, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x6f, 0x6c, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( diff --git a/pkg/protocol/admin/admin.proto b/pkg/protocol/admin/admin.proto index 86063aa03..4c75b99ef 100644 --- a/pkg/protocol/admin/admin.proto +++ b/pkg/protocol/admin/admin.proto @@ -25,6 +25,7 @@ option go_package = "github.com/openimsdk/chat/pkg/protocol/admin"; message LoginReq { string account = 1; string password = 2; + string version = 3; } message LoginResp { From 14ae78fd1e9948f39b6974fa6514c515a6084563 Mon Sep 17 00:00:00 2001 From: icey-yu <119291641+icey-yu@users.noreply.github.com> Date: Thu, 15 May 2025 09:32:01 +0800 Subject: [PATCH 35/36] fix: verify mail constant (#660) --- internal/rpc/chat/login.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/internal/rpc/chat/login.go b/internal/rpc/chat/login.go index 5c4007d4d..490b2edb1 100644 --- a/internal/rpc/chat/login.go +++ b/internal/rpc/chat/login.go @@ -85,6 +85,26 @@ func (o *chatSvr) SendVerifyCode(ctx context.Context, req *chat.SendVerifyCodeRe if o.SMS == nil && o.Mail == nil { return &chat.SendVerifyCodeResp{}, nil // super code } + if req.Email != "" { + switch o.conf.Mail.Use { + case constant.VerifySuperCode: + return &chat.SendVerifyCodeResp{}, nil // super code + case constant.VerifyMail: + default: + return nil, errs.ErrInternalServer.WrapMsg("email verification code is not enabled") + } + } + + if req.AreaCode != "" { + switch o.conf.Phone.Use { + case constant.VerifySuperCode: + return &chat.SendVerifyCodeResp{}, nil // super code + case constant.VerifyALi: + default: + return nil, errs.ErrInternalServer.WrapMsg("phone verification code is not enabled") + } + } + isEmail := req.Email != "" var ( code = o.genVerifyCode() From d9bc41c473a47715e30de6b7f178f601daf1af4a Mon Sep 17 00:00:00 2001 From: icey-yu <119291641+icey-yu@users.noreply.github.com> Date: Thu, 29 May 2025 14:49:47 +0800 Subject: [PATCH 36/36] fix: agent send msg in group && delete conv_resp_id (#663) * fix: robot * fix: db --- internal/api/bot/bot.go | 177 ++++++++++++++++++ internal/rpc/bot/send.go | 92 +++++++++ .../db/model/bot/conversation_resp_id.go | 50 +++++ 3 files changed, 319 insertions(+) create mode 100644 internal/api/bot/bot.go create mode 100644 internal/rpc/bot/send.go create mode 100644 pkg/common/db/model/bot/conversation_resp_id.go diff --git a/internal/api/bot/bot.go b/internal/api/bot/bot.go new file mode 100644 index 000000000..afbe6fdbd --- /dev/null +++ b/internal/api/bot/bot.go @@ -0,0 +1,177 @@ +package bot + +import ( + "encoding/json" + "sort" + "strings" + + "github.com/gin-gonic/gin" + "github.com/openimsdk/chat/internal/api/util" + "github.com/openimsdk/chat/pkg/botstruct" + "github.com/openimsdk/chat/pkg/common/imwebhook" + "github.com/openimsdk/chat/pkg/protocol/bot" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/tools/a2r" + "github.com/openimsdk/tools/apiresp" + "github.com/openimsdk/tools/errs" + "golang.org/x/sync/errgroup" +) + +func New(botClient bot.BotClient, api *util.Api) *Api { + return &Api{ + Api: api, + botClient: botClient, + } +} + +type Api struct { + *util.Api + botClient bot.BotClient +} + +func (o *Api) CreateAgent(c *gin.Context) { + a2r.Call(c, bot.BotClient.CreateAgent, o.botClient) +} + +func (o *Api) DeleteAgent(c *gin.Context) { + a2r.Call(c, bot.BotClient.DeleteAgent, o.botClient) +} + +func (o *Api) UpdateAgent(c *gin.Context) { + a2r.Call(c, bot.BotClient.UpdateAgent, o.botClient) +} + +func (o *Api) PageFindAgent(c *gin.Context) { + a2r.Call(c, bot.BotClient.PageFindAgent, o.botClient) +} + +func (o *Api) AfterSendSingleMsg(c *gin.Context) { + var ( + req = imwebhook.CallbackAfterSendSingleMsgReq{} + ) + + if err := c.BindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) + return + } + if req.ContentType != constant.Text { + apiresp.GinSuccess(c, nil) + return + } + isAgent := botstruct.IsAgentUserID(req.RecvID) + if !isAgent { + apiresp.GinSuccess(c, nil) + return + } + + var elem botstruct.TextElem + err := json.Unmarshal([]byte(req.Content), &elem) + if err != nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("json unmarshal error: "+err.Error())) + return + } + convID := getConversationIDByMsg(req.SessionType, req.SendID, req.RecvID, "") + + key, ok := c.GetQuery(botstruct.Key) + if !ok { + apiresp.GinError(c, errs.ErrArgs.WithDetail("missing key in query").Wrap()) + return + } + res, err := o.botClient.SendBotMessage(c, &bot.SendBotMessageReq{ + AgentID: req.RecvID, + ConversationID: convID, + ContentType: req.ContentType, + Content: elem.Content, + Ex: req.Ex, + Key: key, + }) + if err != nil { + apiresp.GinError(c, err) + return + } + apiresp.GinSuccess(c, res) +} + +func (o *Api) AfterSendGroupMsg(c *gin.Context) { + var ( + req = imwebhook.CallbackAfterSendGroupMsgReq{} + ) + if err := c.BindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) + return + } + + if req.ContentType != constant.AtText { + apiresp.GinSuccess(c, nil) + } + key, ok := c.GetQuery(botstruct.Key) + if !ok { + apiresp.GinError(c, errs.ErrArgs.WithDetail("missing key in query").Wrap()) + return + } + + var ( + elem botstruct.AtElem + reqs []*bot.SendBotMessageReq + ) + + convID := getConversationIDByMsg(req.SessionType, req.SendID, "", req.GroupID) + err := json.Unmarshal([]byte(req.Content), &elem) + if err != nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("json unmarshal error: "+err.Error())) + } + for _, userID := range elem.AtUserList { + if botstruct.IsAgentUserID(userID) { + reqs = append(reqs, &bot.SendBotMessageReq{ + AgentID: userID, + ConversationID: convID, + ContentType: req.ContentType, + Content: elem.Text, + Ex: req.Ex, + Key: key, + }) + } + } + if len(reqs) == 0 { + apiresp.GinSuccess(c, nil) + } + + g := errgroup.Group{} + g.SetLimit(min(len(reqs), 5)) + for i := 0; i < len(reqs); i++ { + i := i + g.Go(func() error { + _, err := o.botClient.SendBotMessage(c, reqs[i]) + if err != nil { + return err + } + return nil + }) + } + + err = g.Wait() + if err != nil { + apiresp.GinError(c, err) + return + } + + apiresp.GinSuccess(c, nil) +} + +func getConversationIDByMsg(sessionType int32, sendID, recvID, groupID string) string { + switch sessionType { + case constant.SingleChatType: + l := []string{sendID, recvID} + sort.Strings(l) + return "si_" + strings.Join(l, "_") // single chat + case constant.WriteGroupChatType: + return "g_" + groupID // group chat + case constant.ReadGroupChatType: + return "sg_" + groupID // super group chat + case constant.NotificationChatType: + l := []string{sendID, recvID} + sort.Strings(l) + return "sn_" + strings.Join(l, "_") + } + return "" +} diff --git a/internal/rpc/bot/send.go b/internal/rpc/bot/send.go new file mode 100644 index 000000000..ba1084760 --- /dev/null +++ b/internal/rpc/bot/send.go @@ -0,0 +1,92 @@ +package bot + +import ( + "context" + "encoding/json" + "time" + + "github.com/openimsdk/chat/pkg/botstruct" + "github.com/openimsdk/chat/pkg/common/imapi" + "github.com/openimsdk/chat/pkg/common/mctx" + "github.com/openimsdk/chat/pkg/protocol/bot" + "github.com/openimsdk/protocol/constant" + "github.com/openimsdk/tools/errs" + "github.com/sashabaranov/go-openai" +) + +func (b *botSvr) SendBotMessage(ctx context.Context, req *bot.SendBotMessageReq) (*bot.SendBotMessageResp, error) { + agent, err := b.database.TakeAgent(ctx, req.AgentID) + if err != nil { + return nil, errs.ErrArgs.WrapMsg("agent not found") + } + //convRespID, err := b.database.TakeConversationRespID(ctx, req.ConversationID, req.AgentID) + //if err != nil && !errors.Is(err, mongo.ErrNoDocuments) { + // return nil, err + //} + //var respID string + //if convRespID != nil { + // respID = convRespID.PreviousResponseID + //} + + aiCfg := openai.DefaultConfig(agent.Key) + aiCfg.BaseURL = agent.Url + aiCfg.HTTPClient = b.httpClient + client := openai.NewClientWithConfig(aiCfg) + aiReq := openai.ChatCompletionRequest{ + Model: agent.Model, + Messages: []openai.ChatCompletionMessage{ + { + Role: openai.ChatMessageRoleSystem, + Content: agent.Prompts, + }, + { + Role: openai.ChatMessageRoleUser, + Content: req.Content, + }, + }, + } + aiCtx, cancel := context.WithTimeout(ctx, time.Duration(b.timeout)*time.Second) + defer cancel() + completion, err := client.CreateChatCompletion(aiCtx, aiReq) + if err != nil { + return nil, errs.Wrap(err) + } + + imToken, err := b.imCaller.ImAdminTokenWithDefaultAdmin(ctx) + if err != nil { + return nil, err + } + ctx = mctx.WithApiToken(ctx, imToken) + + content := "no response" + if len(completion.Choices) > 0 { + content = completion.Choices[0].Message.Content + } + err = b.imCaller.SendSimpleMsg(ctx, &imapi.SendSingleMsgReq{ + SendID: agent.UserID, + Content: content, + }, req.Key) + if err != nil { + return nil, err + } + + //err = b.database.UpdateConversationRespID(ctx, req.ConversationID, agent.UserID, ToDBConversationRespIDUpdate(completion.ID)) + //if err != nil { + // return nil, err + //} + return &bot.SendBotMessageResp{}, nil +} + +func getContent(contentType int32, content string) (string, error) { + switch contentType { + case constant.Text: + var elem botstruct.TextElem + err := json.Unmarshal([]byte(content), &elem) + if err != nil { + return "", errs.ErrArgs.WrapMsg(err.Error()) + } + return elem.Content, nil + default: + return "", errs.New("un support contentType").Wrap() + } +} diff --git a/pkg/common/db/model/bot/conversation_resp_id.go b/pkg/common/db/model/bot/conversation_resp_id.go new file mode 100644 index 000000000..5d35136ab --- /dev/null +++ b/pkg/common/db/model/bot/conversation_resp_id.go @@ -0,0 +1,50 @@ +package bot + +import ( + "context" + + "github.com/openimsdk/chat/pkg/common/db/table/bot" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/errs" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +func NewConversationRespID(db *mongo.Database) (bot.ConversationRespIDInterface, error) { + coll := db.Collection("conversation_resp_id") + _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ + Keys: bson.D{ + {Key: "conversation_id", Value: 1}, + {Key: "agent_id", Value: 1}, + }, + Options: options.Index().SetUnique(true), + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &ConversationRespID{coll: coll}, nil +} + +type ConversationRespID struct { + coll *mongo.Collection +} + +func (o *ConversationRespID) Create(ctx context.Context, elems ...*bot.ConversationRespID) error { + return mongoutil.InsertMany(ctx, o.coll, elems) +} + +func (o *ConversationRespID) Take(ctx context.Context, convID, agentID string) (*bot.ConversationRespID, error) { + return mongoutil.FindOne[*bot.ConversationRespID](ctx, o.coll, bson.M{"conversation_id": convID, "agent_id": agentID}) +} + +func (o *ConversationRespID) Update(ctx context.Context, convID, agentID string, data map[string]any) error { + if len(data) == 0 { + return nil + } + return mongoutil.UpdateOne(ctx, o.coll, bson.M{"conversation_id": convID, "agent_id": agentID}, bson.M{"$set": data}, false, options.Update().SetUpsert(true)) +} + +func (o *ConversationRespID) Delete(ctx context.Context, convID, agentID string) error { + return mongoutil.DeleteMany(ctx, o.coll, bson.M{"conversation_id": convID, "agent_id": agentID}) +}